Skip to content

Latest commit

 

History

History
474 lines (364 loc) · 22.9 KB

BECKN-007-The-XInput-Schema.md

File metadata and controls

474 lines (364 loc) · 22.9 KB

The XInput Schema

CWG Working Draft - November 08, 2022

Document Details

This version

https://github.com/beckn/protocol-specifications/blob/release-1.x/docs/BECKN-007-The-XInput-Schema.md

Latest published version

TODO

Latest editor's draft

TODO

Implementation report

TODO

Editors

Ravi Prakash (Beckn Foundation)

Authors

Ravi Prakash (Beckn Foundation)

Feedback

Issues: TODO Discussions: TODO PRs: TODO

Errata

No Errata exists as of now

Context

Beckn protocol defines a domain-agnostic specification that can be used to represent any customer- provider transaction by implementing a standard set of APIs and schema. Creating a transaction ideally involves the customer discovering products and services offered by various providers, selecting the desired products or services, obtaining the terms of service and payment, and then finally confirming the order. But sometimes, the provider might require additional metadata in order to confirm a transaction. This requirement may be due to legal requirements imposed by the regulatory authorities, or business requirements to allow better serviceability.

For example, a logistics service provider might require additional information from the logistics customer (like a restaurant) like the dimensions of the package, category of items (food, flammable, fragile etc), approximate weight of the package, the order Number etc,

to confirm the order. All of this information needs to be transmitted to the person availing the logistics service.

Similarly, a healthcare service might want the patient to provide information like, their medical history, a description of their symptoms, details of the insurance, etc, before confirming the order.

The nature of additional information required could vary significantly across sectors. These fields could be varied and many, and adding them as protocol attributes would make the protocol bulky and cluttered.

Problem

We require an object that captures additional information (over and above what has been published in the catalog) from the customer regarding the item being ordered without extending the core transaction protocol.

Solution

It is probably not such a good idea to transmit such required data fields as first class citizens of the transaction protocol, rather transmit them in some sort of a custom form object. This form could be a simple HTML form hosted on a url endpoint or transmitted as a whole as per standard form specifications like XForms 2.0.

The proposed design of this feature is as follows.

It starts with a schema called XInput of type Form. The definition of Form is also shown here among other relevant schemas.

 XInput:
   type: object
   properties:
     form:
       $ref: Form
     required:
       description: Indicates whether the form data is mandatorily required by the BPP to confirm the order. 
       type: boolean
       default: true

 Form:
   description: Describes a form that needs to be rendered to the BAP user before the confirmation of an order.
   type: object
   properties:
     url:
       description: The URL from where the form can be fetched. The content fetched from the url must be processed as per the mime_type specified in this object. The BAP can choose to render the form as-is as an embeddable element, or process it further to blend it with the style of the application. In case the interface is non-visual, the BAP can process the form data and reproduce it as per the UI requirements.
       type: string
       format: uri
     mime_type:
       description: This field indicates the nature and format of the form received by querying the url. MIME types are defined and standardized in IETF's RFC 6838. If the mime_type is text/html, the application must render it inside a web view. If the mime_type is application/xml, then the application must consider it as an xForms 2.0 object and render it as per the XForms 2.0 specification.
       type: string
       enum:
       - text/html
       - application/xml
     submission_id:
       type: string
       format: uuid

 FormResponse:
    description: Describes the response to a form submission
    type: object
    properties:
        status:
            description: Contains the status of form submission.
            type: boolean
            default: true
        submission_id:
            description: This contains a UUID generated by the BPP on successful submission of the form. 
            type: string
            format: uuid
        errors:
            type: array
            items:
                $ref: Error

 Error:
   description: Describes an error object returned by the API in case of an exception scenario. The exception may be a technical one like a schema or a signature verification error; or business-related like an item not found, or an agent not available.
   type: object
   properties:
     code:
       type: string
       description: For full list of error codes, refer to docs/protocol-drafts/BECKN-RFC-005-ERROR-CODES-DRAFT-01.md of this repo
     path:
       type: string
       description: Path to json schema generating the error. Used only during json schema validation errors
     message:
       type: string
       description: Human readable message describing the error. Used mainly for logging. Not recommended to be shown to the user.
   required:
     - code
     - path

Usage

The XInput object can be found in the following schemas

  1. Item
  2. Order
  3. Feedback
  4. CancellationTerm

Usage in the Item schema

Item:
    type: object
    properties:
        xinput:
            $ref: '#/components/schemas/XInput'
        ...

This usage means that the BAP user is expected to provide additional information over and above the ID of

Usage in the Order schema

Order:
    type: object
    properties:
        xinput:
            $ref: '#/components/schemas/XInput'
        ...

#### Usage in the `CancellationTerm` schema

CancellationTerm: type: object properties: xinput: $ref: '#/components/schemas/XInput' ...

### Recommendations for BPPs

The following recommendations are for BPPs who will create the form to be rendered on BAPs and receive the submissions from it. 


#### Declaring the form 

- BPPs that require additional information pertaining to individual items being ordered to confirm an order, must send the `xinput` object in the `Item` schema with a form object containing a link to the form with item-specific fields. For example, a person buying an airline ticket containing two flights - an onward Journey by Etihad and a return journey by Lufthansa might have to provide his Etihad membership code for his onward journey. For his return journey, Lufthansa might require them to declare their luggage dimensions, and upload a Covid-19 vaccination certificate. 
- If BPPs require additional information pertaining to the order as a whole, they must send the xinput object in the Order schema containing a link to the form with order-specific information. For example, a cash on delivery grocery order from a store might require the store owner to declare the amount to be collected, the number of items, package category, and the weight of the package before placing the order. 
- If the form is cacheable, then it is recommended for BPPs to send the form link during `on_search` itself.
- If the form is dynamic, then it is recommended for BPPs to send the form link during `on_select`, or `on_init` wherever applicable.


#### Modeling the form

- BPPs can model the form in two ways namely, a) using HTML5 Forms, or b) xForms 2.0 objects
- For creating HTML Forms, please refer to [this](https://www.w3schools.com/html/html_forms.asp) tutorial
- For creating xForms 2.0 Forms, please refer to [this](https://www.w3.org/TR/xforms20/) specification
- Networks can mandate only one, or both types of form specification. (For new networks, it is recommended to start with HTML forms)
- For HTML forms the submission url will be present in the action attribute of the form tag as highlighted in the example below
<form action="http://example.com/submitForm" method="post"> … </form>
- For xForms 2.0 forms, the submission url will be present in the action attribute of the xform:submissions tag as highlighted in the example below
<xforms:submission action="http://example.com/submitForm" method="post"** includenamespaceprefixes=""/>
- It is _not recommended_ for BPPs to send `script` tags along with HTML forms as it will pose a security concern for BAPs
- It is _not recommended_ for BPPs to send `style` tags along with HTML forms as BAPs may re-render the form as per their UI
- It is _not recommended_ for BPPs to send `button` tags along with HTML forms as BAPs may render the CTA for form submission according to their UI
- For XForms 2.0 submissions, the BPP can send the &lt;xforms:submission /> tag to specify submission URL, but it will not be rendered at the BAP. 


#### Handling form requests

- The form must be hosted on a trusted url, preferably with the same domain name as the BPP’s subscriber_id to avoid security-related errors thrown by BAPs. 
- When requested on HTTP, the BPPs must return Content-type: text/html or application/xml in the response body headers. 
- It is _recommended_ to send a unique nonce value in UUID format whenever it receives a form request from a BAP and persist it until a submission matches the nonce or the form expires


#### Handling form submissions

- The form submission method must always be a HTTP/POST when using HTTP as a transport layer. Example: `<form action="url" method="post">`
- The form submission API must also be on the same domain name as the BPP subscriber_id to avoid security-related errors thrown by BAPs
- Form submission request should be digitally signed by the BAP
- The following algorithm must be executed at the BPP when the form is submitted on HTTP/POST, 
- Check if signature is valid
- Check if the nonce value exists and is not expired
- If the nonce value exists and is not expired
    * Validate the form inputs
    * Generate a **FormResponse** object and return it as an `application/json` response
- BPPs must persist this UUID at their ends so that they can match each submission with the corresponding confirm API call


#### Linking form submission to existing transactions

* After successful form submissions, the BPP should ideally receive a confirm API call containing references to the submissions.
* The form submission references can be found in Order.items[ ].xinput_required.form.submission_id, and Order.xinput_required.form.submission_id fields.


#### Discarding Form Submissions
* The BPP can choose to discard the form submissions if the confirm API call does not arrive within a specified time window after the form has been submitted


### Recommendations for BAPs
The following recommendations are for BAPs who will render the form to its users and send the submissions to the BPPs. 


#### Identifying form declarations
* BAPs can identify required item-specific form inputs by parsing the Item schema received in on_search callbacks.
* BAPs must also check for required order-specific form inputs by parsing the Order schema received in on_select, and on_init callbacks.
* The BAP may choose to cache the form by calling the `{Item}.xinput.form.url` endpoint from its API endpoint.
* It should expect either an HTML or an Xforms 2.0 object as a response. If the response body header has Content-type: text/html, then it should expect an HTML form object. If it is application/xml, it should expect an xForms 2.0 model object.


#### Rendering the form
* BAPs should render their forms typically any time before confirming the order
* For item-specific inputs, BAPs should typically render the form when the user selects the item for ordering
* For order-specific inputs, BAPs should typically render the form
* BAPs should remove any script, style, and button tags when rendering the form inside their own UI


#### Submitting the form
* BAPs should submit the form data on the submission url specified in the form object via a HTTP/POST request.
* For HTML forms the submission url will be present in the action attribute of the form tag as highlighted in the example below
… ```
  • For xForms 2.0 forms, the submission url will be present in the action attribute of the xform:submissions tag as highlighted in the example below
<xforms:submission **action="http://example.com/submitForm"** **method="post"** id="submit" includenamespaceprefixes=""/>
  • When submitting the form, the BAPs must digitally sign the request body in the request header
  • All form submissions must be digitally signed by the BAP

Handling form submission responses

  • Form responses are received in the FormResponse object
  • The FormResponse object contains status, submission_id and an error array
  • After receiving the form response, the BAP should execute the following algorithm
    If FormResponse.status is true
    	save the submission_id
    Else
    	throw an exception based on the data inside the error object

Post-Form Submission

After successful submission of the form, the BAP must ideally, send the submission_id received in the previous submission and send it in the corresponding item’s xinput.form.submission_id field, in the confirm API.

Recommendations for Network Facilitators

  • Network Faciliators should publish a list of supported fields with their datatypes that can be used to create forms. This is to reduce form misuse through over-collection of data, and privacy protection.
  • These fields can be the same as supported Tags list published by networks
  • The IDs of the inputs are the codes

Examples

The following examples show how XInput can be used by BPPs to collect additional information from the user before confirming the order.

Example 1 : A logistics provider wants additional information on the nature of the package just before placing the order

In this example, the Logistics BPP can create a XInput object containing a link the the following form

   <form action="https://api.example-bpp.com/sendPackageDetails" method="post">
     <label for="itemCount">Number of items</label>
     <input type="number" id="itemCount" name="itemCount" value="0" />
     <label for="plength">Package length in cm</label>
     <input type="number" id="plength" name="plength" value="0" />
     <label for="pwidth">Package width in cm</label>
     <input type="number" id="pwidth" name="pwidth" value="0" />
     <label for="pheight">Package height in cm</label>
     <input type="number" id="pheight" name="pheight" value="0" />
     <label for="itemCategory">Select your degree</label>
     <select name="itemCategory" id="itemCategory">
       <option value="fnb">Food and Beverages</option>
       <option value="bns">Books and Stationery</option>
       <option value="etg">Electronic Goods</option>
       <option value="hhg">Household goods</option>
     ><br/><br/>
     <input type="hidden" id="nonce" name="nonce" value="t8923y4ryu328473y4" />
   </form>

Let us assume this form is hosted at - https://api.example-bpp.com/getForm?id=t8923y4ryu328473y4

The BPP can choose to send this form at an Item level or at an order level. To keep things simple, let us send this form at an order level.

Let us assume, the Logistics BAP has already declared the intent (via search), received the catalogs (via on_search), selected a specific item ( via select), and has received a quote(via on_select).

Form identification

When the BAP calls init, the Logistics BPP sends the following order object

{
   "context" : {
       "action" : "on_init",
       ...// other context details
   },
   "message" : {
       "order" : {
           "items" : [
               {
                   "id" : "4aa3feca-96b5-47dd-a233-f7fd2525922c",
                   "descriptor" : {
                       "name" : "Hyperlocal delivery"
                   },
                   "price" : {
                       "value" : "50",
                       "currency" : "INR"
                   }
               }
           ],
           "xinput" : {
               "form" : {
                   "url" : "https://api.example-bpp.com/getForm?id=t8923y4ryu328473y4",
                   "mime_type" : "text/html"
               }
           },
           "billing" : {
               ...// billing details
           },
           "fulfillment" : {
               ...// fulfillment details
           },
           ...// other order level details
       }
   }
}

Form Fetching from BPP

When the Logistics BAP receives this object via on_init, it must pull the form data from the order.xinput.form.url field and render the form on the UI. It is recommended that the Logistics BAP keeps watching for the xinput field at the item and order level.

Form Rendering on the BAP

Once pulled the BAP can render the form as-is on its UI, but it is not recommended, as doing so would result in a sub-optimal user experience. This is how the form will look if the BAP renders the form as-is using an HTML parser.

However, the BAP application can apply any styling framework (like css) on the form and render it as per the style guide of the application.

This form must be rendered just before firing the confirm API. This is typically just before checkout, when the BAP invokes the payment flow.

The BAP must render the submit button for this form. This submit button functionality can be merged with the final checkout button or placed exclusively for this form as part of a two-step process.

For example, in the case of a two step process, the flow might look like this

  • Step 1:

    • 1.1 Render form with the first button
    • 1.2 Capture form data and submit it to BPP
    • 1.3 Save submission_id if submission is successful
  • Step 2:

    • 2.1 Render the final confirmation screen with final checkout button
    • 2.2 Fire confirm along with the submission_id reference in the order object

In the case of a one step process, the BAP can collect all the data on a single form and then fire two consecutive API calls, one to submit the form, and the other to confirm the order.

In any case, the form submission id must be transmitted along with the confirm API call.

The BPP will receive the confirm call with the submission_id as reference. It will verify the submission against the submission_id and link that data along with the confirm API.

Now the BPP has all the information required to confirm the order. It can either go ahead with the confirmation or reject the request if applicable.

Example 2: A health & wellness service provider wants additional information about the patient's symptoms before confirming a teleconsultation appointment. The provider and customer are on apps that are DHP-enabled (beckn protocol for health and wellness).

[TODO]

Example 3: A recruitment agency wants additional information about the candidate before confirming a job application. The provider and customer are on apps that are DSEP-enabled (beckn protocol for education and skilling).

   <form action="https://api.example-bpp.com/candidateDetails" name="job_application" method="post">
     <label for="locationPreference">Select you preferred location of work</label>
     <select name="backend_technologies" id="example-bpp.com/locationPreference">
       <option value="std:011">Delhi</option>
       <option value="std:080">Bangalore</option>
       <option value="remote">Remote</option>
     >
     <label for="experience">Years of experience</label>
     <input type="number" id="years_of_experience" name="experience" value="0" />
     <label for="backend_technologies">Select the technologies that you have experience in</label>
     <select name="backend_technologies" id="example-bpp.com/backend_technologies" multiple>
       <option value="php">PHP</option>
       <option value="ruby_on_rails">Ruby on Rails</option>
       <option value="node_js">Node JS</option>
       <option value="python">Python</option>
     >
     <label for="other_technologies">Select any other technologies that you are profient in</label>
     <input type="text" id="example-bpp.com/other_technologies" name="other_technologies" value="0" />
     <input type="hidden" id="nonce" name="nonce" value="t8923y4ryu328473y4" />
   </form>

Example 4: A flight booking system wants the passenger to declare his Covid vaccination status before confirming the booking.

   <form action="https://api.example-bpp.com/covidDeclaration" name="covid_declaration_form" method="post">
     <input type="radio" id="vaccinated" name="vaccination_status" value="true">
     <label for="vaccinated">Yes</label>
     <input type="radio" id="not_vaccinated" name="vaccination_status" value="false">
     <label for="not_vaccinated">No</label>
     <label for="from_addr">Enter the address you are travelling from </label>
     <input type="text" id="from_addr" name="from_address" />
     <label for="from_addr">Enter the address where you are travelling to</label>
     <input type="text" id="from_addr" name="to_address" />
     <input type="hidden" id="nonce" name="nonce" value="t8923y4ryu328473y4" />
   </form>

Example 5: A mentor can seek additional information about a mentee before accepting the mentee's request for enrollment into the session(1-1 session as well as 1-many sessions). The provider and customer are on apps that are DSEP-enabled (Beckn protocol for education and skilling).

In this case, the on_init BPP passes the form URL to BAP, which is rendered and filled by the mentee on BAP. The BAP then sends the acknowledgment ID received after the submission of the form in the confirm API call to BPP.

An example of a form can be as below:-

    <form action="https://api.example-bpp.com/sendMenteeInformation" method="post">
        <label for="resume">Bio of Mentee</label>
        <input type="file" id="resume" name="resume" multiple="true" />
        <label for="experience">Experience in No Of Years </label>
        <input type="text" id="experience" name="experience" value="0" />
        <label for="recommendationLetter">Recommendation Letter from any organisation</label>
        <input type="file" id="recommendationLetter" name="recommendationLetter" multiple="false" />
        <label for="degree">Select your degree</label>
        <select name="degree" id="degree">
            <option value="BTECH">Btech in Computer Science</option>
            <option value="PHD">PHD in Computer Science</option>
            <option value="MS">Masters in Computer Science</option>
        </select>
        <input type="hidden" id="nonce" name="nonce" value="t8923y4ryu328473y4" />
   </form>

Acknowledgements

The authors would like to thank the following people for their support and contributions to this document.

  • Venkataramanan Mahadevan (Humbhionline)
  • Pramod Varma (Beckn Foundation)
  • Sujith Nair (Beckn Foundation)
  • Akash Shah (Shikshalokam)
  • Sankarshan Mukhopadyay (Dhiway Networks)