Callbacks¶
API clients can associate some resources with a callback_uri in order to enable asynchronous communication between the client and server. At certain events mCASH can trigger a callback to specified callback_uri. E.g. if the callback URI is an HTTP URI, an HTTP POST request will be made to the URI. The data sent with the callback is referred to as a "callback message" (or just "message"). The message consists of a meta part and an object part, the latter containing the actual message data, while the former is meta information about the callback. Note that you do not have to know everything about callbacks in order to implement an API client. However, all developers should read the Security considerations section.
Callbacks support several protocols (see Supported protocols) For protocols that are considered secure the callback will contain the entire message. Let us first consider an example where the callback is made using a secure protocol. The example callback_uri of the resource is https://callbackserver.test/notification/qWeR/, which is an HTTPS URI.
POST /notification/qWeR/ HTTP/1.1
HOST: callbackserver.test
Content-Type: application/vnd.mcash.api.merchant.v1+json
Authorization: RSA-SHA256 <rsa_signature>
X-Mcash-Content-Digest: SHA256=<content_sha256>
{
"meta": {
"id": "RzeUPFP1T5WkWd46tX8Hxg",
"event": "test_event",
"uri": "https://server.test/my_resource/1/"
},
"object": {"text": "Hello World"},
}
Notice the headers Authorization and X-Mcash-Content-Digest. The values of these headers contain the information necessary for the client to authenticate the callback from mCASH. See Verifying signatures from mCASH for a description of the signature method used in requests from mCASH.
For insecure protocols, mCASH will only send non-sensitive meta-information. In this example the callback_uri is http://callbackserver.test/notification/qWeR/ (HTTP):
POST /notification/qWeR HTTP/1.1
HOST: callbackserver.test
Content-Type: application/vnd.mcash.api.merchant.v1+json
{
"meta": {
"id": "RzeUPFP1T5WkWd46tX8Hxg",
"event": "test_event",
"uri": "https://server.test/my_resource/1/"
}
}
Here the uri field contains a URI that points to an endpoint on an mCASH server where the object part can be retrieved using an HTTPS GET.
GET /my_resource/1/ HTTP/1.1
HOST: server.test
HTTP/1.1 200 OK
Content-Type: application/vnd.mcash.api.merchant.v1+json
{"text": "Hello World"}
Events¶
The value in the event field in the meta part of the message is called the message event or just event. The event says something about why the callback was made and how to interpret the object part (a data schema is defined for each event).
Payment request¶
Several events are associated with the different transitions in payment request state:
- payment_authorized (User has accepted a payment request. Used for both AUTH and SALE requests)
- payment_captured
- payment_auth_released
- payment_aborted_by_customer
- payment_aborted_by_merchant
- payment_authorization_renewed
- payment_authorization_expired
- payment_request_expired
As these events reflect the state of the payment request at the time the callback was made, the object part will contain the same data as what can be retrieved from the payment request outcome endpoint. The data schema is:
-
currency : Currency : required - Data required (new or existing on update)
- length == 3
3 chars https://en.wikipedia.org/wiki/ISO_4217 amount : Money : optional : default=null Amount additional_amount : Money : optional : default=null Additional amount might have been changed by user if additional_edit was true auth_amount : Money : optional : default=null The authorized amount. If doing partial captures, this will show the amount still available in the authorization for subsequent captures; auth_amount = amount - sum(captured amounts) auth_additional_amount : Money : optional : default=null The authorized additional amount. If doing partial captures, this will show the part of additional amount still available in the authorization for subsequent captures; auth_additional_amount = additional_amount - sum(captured additional amounts) captures[] : Capture : optional : default=null List of captures. refunds[] : Refund : optional : default=null List of refunds. status : String : optional : default=null - Value in ok, fail, auth, pending
Payment request status (see above) status_code : Integer : optional : default=null Payment request status code (see above). customer : PersonIdentifier : optional : default=null Customer identifier as originally registered by POS. date_modified : DateTime : optional : default=null Last modified date date_expires : DateTime : optional : default=null Expiration date for current status. After a payment authorization is given this may extend beyond the original expiry date given in the payment request. An authorization expires after 3 days. When the payment request expires it is marked as failed (whether in pending or authorized state). credit : Boolean : optional : default=false Whether the received payment was a credit payment. interchange_fee : Money : optional : default=null Interchange fee to be deducted if credit payment. transaction_fee : Money : optional : default=null Transaction fee to be deducted. report_id : String : optional : default=null The Report that this transaction is included in. report_uri : String : optional : default=null - Optional
- URL
Endpoint for the report that contains the current state of the payment request. ledger : String : optional : default=null - Optional
ID of ledger this payment request is included in attachment_uri : String : optional : default=null - Optional
- URL
Endpoint for Attachment uploads, such as electronic receipts. This URI has a limited time to live, and a new URI is generated each time outcome is retrieved. pos_id : String : required - Data required (new or existing on update)
The POS this request originates from, used for informing user about origin pos_tid : String : required - Data required (new or existing on update)
Local transaction id for POS. This must be unique for the POS tid : String : required - Data required (new or existing on update)
mCASH transaction id permissions : AccessTokenResponse : optional : default=null If payment request was combined with a permission request, this field will contain the permission request outcome. Same as returned by a GET the permission request outcome endpoint
Permission request¶
There are two events associated with permission requests:
- permission_request_answered (User has processed the request and accepted or declined access to one or more resources)
- permission_request_expired
The same data is available at the outcome endpoint, with response schema:
-
access_token : String : optional : default=null - Optional
Access token id_token : String : optional : default=null - Optional
A JWT that contains identity information about the user that is digitally signed by mCASH token_type : String : required - Data required (new or existing on update)
Type of access token, at this time it will always be Bearer expires_in : Integer : optional : default=null - Optional
Lifetime in seconds of the access token refresh_token : String : optional : default=null - Optional
Refresh token used to issue new access token after expiration scope : String : optional : default=null - Optional
- Value in address, bankid, email, fodselsnummer, openid, phone, profile, shipping_address
Space-delimited list of scopes. Any of: "openid" (static id, "address" (user preferred address), "profile" (name), "phone", "email", "shipping_address", "fodselsnummer" currency : Currency : optional : default=null - Optional
- length == 3
Currency for fee transaction_fee : Money : optional : default="0.00" Permission fee to be deducted from settlement report_id : String : optional : default=null The Report that this authorization is included in report_uri : String : optional : default=null - Optional
- URL
Endpoint for the report that contains the state of the permission request. ledger_id : String : optional : default=null - Optional
DEPRECATED, do not pass status : String : optional : default=null Permission request status status_code : Integer : optional : default=null Permission request status code pos_id : String : required - Data required (new or existing on update)
The POS this request originates from, used for informing user about origin pos_tid : String : required - Data required (new or existing on update)
Local transaction id for POS. This must be unique for the POS rid : String : required - Data required (new or existing on update)
mCASH request id user_info : Json : optional : default=null User Info
Shortlink scan¶
Whenever a shortlink is scanned a callback will be made by mCASH to the URI that was given in the callback_uri field of the shortlink resource. The event for this callback is shortlink_scanned and the data schema for the object part is:
-
id : String : required - Data required (new or existing on update)
The scan token ID that can be used as recipient for payment and permission requests. Expires in one day. argstring : String : optional : default=null The string that was appended to the shortlink value in the QR code that was scanned
Note that this event is exempt from the "secure callback rule". I.e. the object part is always included, no matter what protocol is being used for the callback. Hence the uri field in the meta part is null.
If that callback is made using HTTP or HTTPS, the recipient of the callback may return the following data, which will be transported back to the user agent that scanned the shortlink, in the HTTP(S) response body:
-
text : String : optional : default=null - Optional
Text that will be displayed to user uri : String : optional : default=null - Optional
- URL
URI to open in mCASH App. DEPRECATED, use next action payload instead. next : Json : optional : default=null Next action
Supported protocols¶
The part before the first colon in the callback URI determines the protocol that will be used for the callback. The meaning of the part after the colon depends on the actual protocol. The supported protocols with descriptions are given here.
HTTP¶
Example URI: http://acme.com/payment_request/Qd3/callback/
mCASH will make an HTTP POST request to the specified URI. The content-type of the request will be the API media type, unless a different media type is documented for the particular callback. The request is signed by mCASH according to Authentication using RSA signature.
HTTPS (secure)¶
Example URI: https://acme.com/payment_request/Qd3/callback/
Same as HTTP, except that HTTPS is considered secure which means that the object part is included in the callback message. mCASH verifies SSL certificates, so the recipient of the callback must use a CA signed certificate. If the client is going to use the data in the object part it SHOULD verify that the callback has been correctly signed by mCASH.
HTTPS should be the preferred callback protocol for high-traffic clients, such as web-shops, as it is the protocol that generates least traffic between the client and mCASH.
Pusher¶
Example URI: pusher:m-acme-payment_request-Qd3
Pusher uses a websocket connection that is initiated by the client. Hence, Pusher may be a convenient alternative for clients that are unable to receive HTTP(S) requests or otherwise listen for incoming connections, which is typically the case for clients that connect to the internet through a NAT. Note that Pusher should only be used by clients with relatively low traffic, such as cash registers in a store. High traffic clients, such as web-shops, should use HTTP or HTTPS.
The form of a Pusher URI is pusher:<channel> where <channel> is a placeholder for the pusher channel that mCASH will send the callback message to. Merchants should prefix their channel names with m-<merchant_id>-. The event of the callback message maps to a Pusher event, so if a client for example wants to listen for a shortlink scan it has to bind to the Pusher event shortlink_scanned on the channel where it expects the shortlink scan callback.
Please contact mCASH to obtain the Pusher app key to use with mCASH APIs
Security considerations¶
One important criterion for the mCASH APIs is that the responsibility for security should mostly fall on the server (mCASH) not the client. However, regarding callbacks one responsibility that falls on the client is to verify the origin of the data sent with the callback before putting it to use. There are two ways to do this.
Validation of message URI¶
If the client does not implement signature verification or is using a protocol for callbacks that does not support signatures, the callback can be verified using the following procedure:
- Verify that the hostname in the message URI in the uri field in the meta part is an mca.sh sub-domain and that the URI is HTTPS. I.e. check that the URI starts with "https:" and that the hostname ends with ".mca.sh". Example of a valid URI: https://api.mca.sh/merchant/v1/.
- Retrieve the message by making an HTTPS GET request to the message URI. Make sure that your HTTPS client library is configured to verify SSL certificates. The retrieved message can safely be used as it's origin has been verified through HTTPS.
Note that some of our test environments have hostnames that are not a sub-domain of ".mca.sh", in which case this method will not work.
Verify the callback signature¶
For some protocols, like HTTP and HTTPS, it is specified that mCASH signs the callback. If the client verifies the signature according to the specified signature method, any data sent with the callback can be used safely.