Docs » Synchronization Edit on GitHub

Synchronization

There are two requests in our Synchronization API: Ping and Sequence. Ping is a tiny request that you receive from us, both periodically and after certain events. Sequence is a request that you make when you want to pull changes.

Ping Service

You can configure as many endpoints as you like. We recommend that you use TLS, but this is not a requirement. Pings are HTTP POST requests with the following headers and JSON fields:

HTTP/1.1 headersDescription
X-Signature: 17FUWCstyodDzsCkG5/gU/2VA2vUEcHfvFxGh8RCElo=Base64 encoded HMAC-SHA2-256 signature of the body signed with your API key. Read more.
JSON fieldsDescription
"seq": 23591Global seq counter for your shop. This will increment with every new transaction, capture and refund.
"shopid": 129The shopid associated with this ping.

We will ping you every time your global seq increases and every 5 minutes (periodic pings). You will have to store a local seq counter and use this to determine if your system is synchronized. If this is not the case then you should pull the changes with a Sequence Request. Explained with pseudocode:

if Base64(HMAC-SHA2-256(body, apikey))  headers['X-Signature'] then
    log 'Warning: Invalid ping signature!'
    exit
end
ping := jsondecode(body)
if ping.seq > localseq then
    // Pull changes with a sequence request...
end

Sequence Request

To get changes send a HTTP GET request to https://api.scanpay.dk/v1/seq/$localseq, where $localseq is your locally stored seq counter. Your request will need to have the following header:

HTTP/1.1 headersDescription
Authorization: Basic MTE1MzpZSFpJVUdRdzZOa0NJWWEzbUc2Q1djZ1NobmwxM3h1STdPREZVWXVNeTBqNzkwUTZUaHdCRWp4ZldGWHdKWjBXHTTP Basic authentication. Read more.

Response

All successful responses have a 200 HTTP status code and a JSON object with the following fields:

JSON fieldsDescription
"seq": 23591The seq of the last change in this response. This is your new localseq, but not necessarily your global seq counter.
"changes": [
    {
        "id": 1234,
        "rev": 7,
        "orderid": "abc123",
        "time": {
            "created": 1479384780,
            "authorized": 1479384799
        },
        "acts": [
            {
                "act": "capture",
                "time": 1479384886,
                "total": "100.45 DKK"
            },
            {
                "act": "refund",
                "time": 1479387243,
                "total": "42.78 DKK"
            }
        ],
        "totals": {
            "authorized": "123.45 DKK",
            "captured": "100.45 DKK",
            "refunded": "42.78 DKK",
            "left": "23.00 DKK"
        }
    },
    {
        "id": 5678,
        "error": "datacenter obliterated"
    }
]
An array with zero or more changes since the requested seq, but not necessarily all changes.
  • id: Transaction id.
  • rev: Transaction revision number representing the number of changes made to this transaction. Rev will start at 1 and increment with actions (e.g. capture/refund) and other changes to this transaction.
  • orderid: The orderid that you assigned when you created the payment link (here).
  • time: Unix timestamps.
  • acts: Cumulative array of actions in this transaction.
  • totals: The relevant values for this transaction.
  • error: An error message. You should skip the change if this happens.

Now you will have to loop through the response and apply the changes to your database. It's important that you do this transactionally, and/or handle race conditions. Explained with pseudocode:

data := jsondecode(GET https://api.scanpay.dk/seq/ + localseq)
for trn in data.changes do
    if trn.error is set then
        log trn.error // Contact us if this happens
        continue
    end

    trnid, email := MySQL(
        BEGIN;
        SELECT trnid, email FROM orders
            WHERE trnid = 'trn.id' OR orderid = 'trn.orderid' FOR UPDATE;
        UPDATE orders SET trnid = 'trn.id', rev = 'trn.rev', ...
            WHERE (trnid = 'trn.id' OR orderid = 'trn.orderid') AND rev < 'trn.rev';
        COMMIT;
    )

    if trnid = 0 then
        sendmail(email, "Order confirmation ...")
    end
end

MySQL(UPDATE globals SET seq = 'data.seq' WHERE seq < 'data.seq')