Integrating ECR solutions with Settle

The Settle API supports a number of payment flows suitable for electronic cash register (ECR) integrations. A common use case is to have the customer scan a QR code, which will trigger a callback to the vendor's ERP system or a similar system.

Prerequisites

API key

The merchant must have an API key.

One key is enough, but it is also possible to create several if necessary (if, for example, the merchant has several POS devices and desires separate credentials for all of them for security reasons)

Callback handler

A backend system for receiving QR code scans, see callbacks.

Example

A coffee shop (the merchant) uses a mobile point of sale (POS) system which allows their staff to accept payments at customers' tables. They accept cash, card and Settle.

When a client wishes to pay with Settle, the POS generates a QR code for the customer to scan, which is used by the POS vendor to initiate a payment request.

1. Generating the QR code

The POS generates and displays a QR code which contains the shortlink ID and a transaction ID generated by the vendor's backend system.

Settle expects a scanned QR code to contain a specific URL:

http://settle.eu/s/<shortlink_id>/<vendors_transaction_id>

Note that http://settle.eu/s/<shortlink_id>/ is mandatory, the rest of the URL (vendors_transaction_id) will be sent to the callback handler.

2. QR code scan

When the customer scans the QR code and the scan is registered by Settle, Settle generates a unique scan token which can be used by the vendor's backend system to initiate a payment request.

3. Callback

Settle calls the vendor's specified callback_uri, passing in the scan token which can be used to create a payment request. The 'extra' information encoded in the QR code (vendors_transaction_id in this example) is also present in the payload.

The following is an example of the payload that would be sent to the vendor's backend when a QR code containing http://settle.eu/s/<shortlink_id>/<vendors_transaction_id> is scanned:

{
  "meta": {
    "seqno": 0,
    "labels": [

    ],
    "uri": null,
    "id": "D5S6WYjnQ_ObT-DyZfrVPA",
    "context": "ctx:D5S6WYjnQ_ObT-DyZfrVPA",
    "timestamp": "2019-03-21 08:58:49",
    "event": "shortlink_scanned"
  },
  "object": {
    "id": "token:5632006343884800",
    "argstring": "vendors_transaction_id"
  }
}

The scan token for this scan is token:5632006343884800.

4. Payment request

The vendor initiates a payment request using the scan token that Settle generated as the value in the customer field.

Example payment request for €20, using the scan token from the previous section:

// POST https://api.settle.demo/merchant/v1/payment_request/

{
  "action": "SALE",
  "allow_credit": true,
  "pos_tid": "vendors_transaction_id",
  "pos_id": "id-of-the-pos",
  "customer": "token:5632006343884800",
  "currency": "EUR",
  "amount": 2000
}

Example response:

{
  "id": "p2ybyw4tq73n",
  "uri": null
}

Note that the id field in the response is Settle's transaction id (tid), which is used to identify the payment in future API calls.

After creating the payment request, the vendor should poll the payment outcome endpoint, and monitor status changes. A newly created payment request will have status_code set to 1003 (PENDING).

Example outcome with status 1003 (PENDING):

// GET https://api.settle.demo/merchant/v1/payment_request/p2ybyw4tq73n/outcome/

{
  "status": "pending",
  "customer": "token:5632006343884800",
  "attachment_uri": <removed>,
  "pos_tid": "vendors_transaction_id",
  "refunds": [

  ],
  "auth_amount": 0,
  "auth_additional_amount": 0,
  "captures": [

  ],
  "date_modified": "2019-03-21 08:58:49",
  "date_expires": "2019-03-26 08:59:07",
  "credit": false,
  "amount": 2000,
  "interchange_fee": 0,
  "status_code": 1003,
  "tid": "p2ybyw4tq73n",
  "pos_id": "id-of-the-pos",
  "currency": "EUR",
  "additional_amount": 0,
  "transaction_fee": 0,
  "permissions": null
}

5. Payment confirmation

A message appears on the customer's phone asking them to confirm the payment.

If the user confirms the payment, the status_code returned from the payment outcome endpoint changes to 3008 (AUTH):

// GET https://api.settle.demo/merchant/v1/payment_request/p2ybyw4tq73n/outcome/

{
  "status": "auth",
  "customer": "token:5632006343884800",
  "attachment_uri": <removed>,
  "pos_tid": "vendors_transaction_id",
  "refunds": [

  ],
  "auth_amount": 2000,
  "auth_additional_amount": 0,
  "captures": [

  ],
  "date_modified": "2019-03-21 08:58:49",
  "date_expires": "2019-03-26 08:59:07",
  "credit": false,
  "amount": 2000,
  "interchange_fee": 0,
  "status_code": 3008,
  "tid": "p2ybyw4tq73n",
  "pos_id": "id-of-the-pos",
  "currency": "EUR",
  "additional_amount": 0,
  "transaction_fee": 0,
  "permissions": null
}

Note that auth_amount changed from 0 to 2000.

If the user chooses to reject the payment, status_code changes to 5006 (REJECTED).

6. Waiting for authorization

As soon as the customer confirms the payment in their app, Settle will attempt to authorize the payment. When status_code changes to 3008 (AUTH), the payment can be captured.

7. Capturing the payment

The vendor captures the payment using the PUT /payment_request/<tid>/ endpoint, sending in {action: "capture"}:

// PUT https://api.settle.demo/merchant/v1/payment_request/p2ybyw4tq73n/

{
  "action": "capture"
}

Note that the payment must be authorized before capture is possible; it is an error to try to capture a payment that does not have status_code 3008 (AUTH).

8. Verifying the capture

Again, polling the payment outcome, the vendor can check the payment's status_code to see whether it succeeded. 2000 (OK) means that the payment is captured and has been transferred to the merchant:

// GET https://api.settle.demo/merchant/v1/payment_request/p2ybyw4tq73n/outcome/

{
  "status": "ok",
  "customer": "token:5632006343884800",
  "attachment_uri": <removed>,
  "pos_tid": "vendors_transaction_id",
  "refunds": [

  ],
  "auth_amount": 2000,
  "auth_additional_amount": 0,
  "captures": [
    {
      "amount": 2000,
      "id": null,
      "additional_amount": 0
    }
  ],
  "date_modified": "2019-03-21 08:58:49",
  "date_expires": "2019-03-26 08:59:07",
  "credit": false,
  "amount": 2000,
  "interchange_fee": 0,
  "status_code": 2000,
  "tid": "p2ybyw4tq73n",
  "pos_id": "id-of-the-pos",
  "currency": "EUR",
  "additional_amount": 0,
  "transaction_fee": 0,
  "permissions": null
}

For a full list of status codes, see the outcome documentation.