NAV
shell
  • Overview
  • API Overview
  • QR Codes
  • Payments
  • Cash Ups
  • Code Snippets
  • Overview

    API Base URL

    https://pos.snapscan.io/merchant/api/v1

    The SnapScan API is REST-like and relies on HTTP status codes to indicate API errors. We support CORS so that you can interact with our API through a client-side web application. We return JSON in all responses from the API.

    WooCommerce, Magento, ShopStar, OpenCart and PayGate integrations available. We also offer a partial integration with Shopify. Please contact help@snapscan.co.za for more information.

    API Overview

    Authentication

    # Authentication through HTTP Basic Auth
    curl -u your-api-key: "api_endpoint_here"
    

    The following response can be expected for unauthorised requests:

    HTTP/1.1 401 UNAUTHORIZED
    Content-Type: application/json
    
    {
      "message": "Unauthorised"
    }
    

    Access to the API is protected through an API key. Authentication occurs via HTTP Basic Auth. The basic auth username must be set to your API key and the password should be left blank.

    All requests must be made over HTTPS and authenticated. Any request over HTTP will fail.

    Error Codes

    Example of an error response when an invalid parameter is provided:

    HTTP/1.1 400 BAD REQUEST
    Content-Type: application/json
    
    {
      "message": "startDate is not valid"
    }
    

    HTTP status codes are use to indicate the success or failure of an API request. In general 2xx indicates success, 4xx indicates failure due to information provided by you (eg. a required parameter is missing) while 5xx indicates that the failure was caused by the SnapScan servers (or we were unable to service the request at this time). A valid error response from us will always be a JSON object containing a message key.

    Pagination

    All API resources that can return multiple records (eg. the payments API) are paginated. These endpoints provide the same set of parameters that allow you to specify which page and how many records per page to return.

    Query Parameters

    Parameter Default Description
    page 1 The current page.
    perPage 50 The number of records to return per page (maximum: 100).
    offset 0 The offset to start from.

    Response Headers

    The following pagination headers are included in the response. All pagination headers are integers.

    Header Description
    X-Total The total number of records in the query.
    X-Total-Pages The number of pages that the query is made up of.
    X-Page The current page.
    X-Per-Page The number of records per page.
    X-Next-Page The next page.
    X-Prev-Page The prev page
    X-Offset The offset being used.

    Rate Limiting

    All calls to our API are rate limited. In the case of your calls being throttled the API will return status code 429.

    It is best to avoid being throttled but in the case that it happens you should use exponential backoff when making requests to prevent constant throttling.

    Webhook

    We recommend that you make use of a webhook to be notified of payment completion due to the real-time nature of the system. During your account set up we can configure a URL to which we will POST payment objects as we determine their status. We will only notify you of completed and errored payments through the webhook.

    Note that webhooks should be treated as an unauthenticated event stream. If payment spoofing is a concern and you require higher levels of certainty about a payment, make an authenticated API call to our get payment (or get all payments) endpoint.

    We POST the data as an application/x-www-form-urlencoded JSON string under the payload key.

    Verifying payload authenticity

    An example of verifying the hash signature in Ruby:

    params do
      requires :payload, String
    end
    post '/snapscan_webhook' do
      # the raw POST body that hasn't been parsed or decoded
      request_body = request.body.read
      verify_signature!(request_body, ENV['WEBHOOK_AUTH_KEY'])
      payload = JSON.parse(params[:payload])
      puts ">>> Received payload: #{payload.inspect}"
    end
    
    def verify_signature!(request_body, webhook_auth_key)
      signature = OpenSSL::HMAC.hexdigest('sha256', webhook_auth_key, request_body)
      auth_signature = "SnapScan signature=#{signature}"
    
      unless Rack::Utils.secure_compare(auth_signature, headers["Authorization"])
        raise "Unauthorized webhook received"
      end
    end
    

    Once you have been provided with a Webhook Authentication Key it will be used to create a hash signature which will be sent along with all webhook payloads. You can use this signature to verify the authenticity of the payload received from us.

    The hash is sent in the HTTP Authorization header and is computed by creating a HMAC hexdigest of the raw request body (ie. the original URL encoded body including the payload key) using SHA256.

    The Authorization header will have the following form:

    SnapScan signature=<hash>

    where <hash> will be replaced with the computed hash.

    When comparing signatures we recommend you use constant time string comparison to avoid certain timing attacks, in Ruby this can be achieved using secure_compare.

    QR Codes

    Creating the URL

    All SnapScan QR codes contain a SnapCode to identify the merchant. Additional parameters amount and id can be included to pre-populate the amount owed and a unique order number on the customers phone. These values will be associated with the payment as requiredAmount and merchantReference in the API.

    Standard SnapCode

    Your unique SnapCode will be displayed on your QR code stand or may be supplied by customer support. Let's say yours is "shopalot", your URL would look as follows:

    Payment Detail URL
    Merchant: Shopalot
    SnapCode: shopalot
    https://pos.snapscan.io/qr/shopalot

    Adding payment parameters

    Used for online checkout, point-of-sale, vending machines and more.

    In some cases, it is useful for the merchant to include the amount owed and a unique reference number to reconcile payments.

    If a merchant wishes to embed the amount and reference of a payment so that this information is pulled through into the users app at payment - they simply add query parameters to the payment URL. For example:

    Payment Detail URL
    Merchant: Shopalot
    SnapCode: shopalot
    ID: Ord123
    Amount: R10.00
    https://pos.snapscan.io/qr/shopalot?id=Ord123&amount=1000

    Limiting successful payments to unique Id

    To prevent the customer from successfully paying the same reference twice, and from paying less than the specified &amount= parameter, simply add &strict=true to the end of a payment URL.

    Payment Detail URL
    Merchant: Shopalot
    SnapCode: shopalot
    ID: Ord123
    Amount: R10.00
    Strict: true
    https://pos.snapscan.io/qr/shopalot?id=Ord123&amount=1000&strict=true

    Adding extra parameters

    You can add extra parameters to the payment URL. These details will be passed back under the extra attribute in payments.

    https://pos.snapscan.io/qr/shopalot?customValue=123

    Generating a QR code

    Use the QR code generator API to display a code on your site. This allows for the specification of the image type as well as the size. See the code snippet to the right as an example.

    An example QR code in HTML:

    <a href="https://pos.snapscan.io/qr/shopalot?id=Ord123&amount=1000">
      <img src="https://pos.snapscan.io/qr/shopalot.svg?id=Ord123&amount=1000&snap_code_size=125">
    </a>
    

    external link

    Payments

    The API's main purpose is to provide you with various ways to query the status of payments that were made against your merchant account.

    Credit card processing can take a few seconds and because the API caters for real-time queries it affects how the API works. If a query contains any pending payments it is necessary to poll the API until the result is available, for real-time applications we recommend that you make use of our webhook service. Seeing as webhooks can fail due to various reasons (eg. timeouts) an integration should allow the client to manually request the status of payments.

    The payment object

    An example of a payment object:

    {
      "id": 1,
      "status": "completed",
      "date": "1999-12-31T23:00:00Z",
      "totalAmount": 1000,
      "tipAmount": 0,
      "requiredAmount": 1000,
      "snapCode": "STB115",
      "snapCodeReference": "Till Point #1",
      "userReference": "John Doe",
      "merchantReference": "INV001",
      "statementReference": "SNAPSCAN 20150109",
      "authCode": "123456",
      "isVoucher": false,
      "isVoucherRedemption": false,
      "extra": {
        "customValue": "123"
      }
    }
    

    Payment objects always have all possible attributes but if an attribute is not defined it will be null.

    The following attributes are provided by all QR codes:

    Attribute Type Description
    id Integer Our unique ID for the payment. The ID is sequential and starts from 1.
    status String Indicates whether the payment was successful or failed. Possible values are: completed, error, pending
    date String The UTC date of when the payment was started. The date is ISO8601 formatted, eg: 1999-12-31T23:00:00Z
    totalAmount Integer The total amount in cents paid by the user.
    tipAmount Integer If this feature is enabled for your account it will include the tip amount in cents paid by the user (totalAmount includes the tipAmount).
    snapCode String The unique reference encoded in the QR code which is linked to your account. The code is always the same for payments made through the QR.
    snapCodeReference String A reference that you can choose to be defined on the QR code which will always be the same for payments made through it.
    userReference String If this feature is enabled for your account it will include the reference defined by the user when he made the payment.
    statementReference String If the payment has been settled into your bank account it will include the statement reference for the associated settlement. This is the reference that will appear on your bank statement.
    isVoucher Boolean Indicates whether or not a voucher was purchased for this payment.
    isVoucherRedemption Boolean Indicates whether or not a voucher was used to perform this payment.
    extra Object Any extra parameters that were sent as part of the payment URL.

    The following attributes will be returned on the payment object if you generate QR codes using the relevant payment parameters specified here:

    Attribute Type Description
    requiredAmount Integer The amount in cents that was required to be paid by the user.
    merchantReference String A unique reference defined by you and encoded in the QR code.
    authCode String A random number that is generated by us for payments that have a required amount and merchant reference defined. The number is 6 digits long and will be displayed to the user if the payment was successful.

    Get all payments

    curl -u your-api-key: "https://pos.snapscan.io/merchant/api/v1/payments"
    

    The above command returns JSON structured like this:

    HTTP/1.1 200 OK
    Content-Type: application/json
    
    [
      {
        "id": 2,
        "status": "error",
        "date": "2000-01-01T01:00:00Z",
        "totalAmount": 2050,
        "tipAmount": 550,
        "requiredAmount": 1500,
        "snapCode": "STB115",
        "snapCodeReference": "Till Point #1",
        "userReference": "Jane Doe",
        "merchantReference": "INV002",
        "statementReference": "SNAPSCAN 20150109",
        "authCode": "654321",
        "extra": null,
      },
      {
        "id": 1,
        "status": "completed",
        "date": "1999-12-31T23:00:00Z",
        "totalAmount": 1000,
        "tipAmount": 0,
        "requiredAmount": 1000,
        "snapCode": "STB115",
        "snapCodeReference": "Till Point #1",
        "userReference": "John Doe",
        "merchantReference": "INV001",
        "statementReference": "SNAPSCAN 20150109",
        "authCode": "123456",
        "extra": null,
      }
    ]
    

    Returns all payments that have been made against your QR codes (SnapCodes). If no parameters are provided all payments made to you will be returned, subject to pagination. By default if the status parameter isn't provided completed, errored and pending payments will be returned.

    A successful response is always an array and is paginated. If no payments match your query parameters the array will be empty. Payments are ordered by descending IDs, ie. the first payment will always be the latest in the returned result.

    HTTP Request

    GET https://pos.snapscan.io/merchant/api/v1/payments

    Query Parameters

    All parameters are optional.

    Parameter Description
    startDate Payments that were started at or after this time, eg: 2000-01-01T01:00:00Z
    endDate Payments that were started before this time, eg: 2000-01-01T01:00:00Z
    status A comma separated string of the following values: completed, error or pending, eg. completed,pending
    snapCode Payments with the SnapCode.
    snapCodeReference Payments with the SnapCode reference.
    userReference Payments with the user reference.
    merchantReference Payments with your reference.
    statementReference Payments included in the settlement with the provided reference.

    Response Codes

    Description HTTP Status JSON Response
    OK 200 Array of payment objects
    Invalid parameter 400 Object containing a message key

    Get a payment

    curl -u your-api-key: "https://pos.snapscan.io/merchant/api/v1/payments/1"
    

    The above command returns JSON structured like this:

    HTTP/1.1 200 OK
    Content-Type: application/json
    
    {
      "id": 1,
      "status": "completed",
      "date": "1999-12-31T23:00:00Z",
      "totalAmount": 1000,
      "tipAmount": 0,
      "requiredAmount": 1000,
      "snapCode": "STB115",
      "snapCodeReference": "Till Point #1",
      "userReference": "John Doe",
      "merchantReference": "INV001",
      "statementReference": "SNAPSCAN 20150109",
      "authCode": "123456",
      "extra": null,
    }
    

    Returns a single payment.

    HTTP Request

    GET https://pos.snapscan.io/merchant/api/v1/payments/{id}

    Route Parameters

    The id route parameter is required.

    Parameter Description
    id The sequential ID of the payment.

    Response Codes

    Description HTTP Status JSON Response
    OK 200 A payment object
    ID doesn't exist 404 Object containing a message key

    Get all cash up payments

    curl -u your-api-key: "https://pos.snapscan.io/merchant/api/v1/payments/cash_ups/1e07ac748d2627ba"
    

    The above command returns JSON structured like this:

    HTTP/1.1 200 OK
    Content-Type: application/json
    
    [
      {
        "id": 3,
        "status": "completed",
        "date": "2000-01-01T01:00:00Z",
        "totalAmount": 2050,
        "tipAmount": 550,
        "requiredAmount": 1500,
        "snapCode": "STB115",
        "snapCodeReference": "Till Point #1",
        "userReference": "Jane Doe",
        "merchantReference": "INV002",
        "statementReference": "SNAPSCAN 20150109",
        "authCode": "654321",
        "extra": null,
      },
      {
        "id": 1,
        "status": "completed",
        "date": "1999-12-31T23:00:00Z",
        "totalAmount": 1000,
        "tipAmount": 0,
        "requiredAmount": 1000,
        "snapCode": "STB115",
        "snapCodeReference": "Till Point #1",
        "userReference": "John Doe",
        "merchantReference": "INV001",
        "statementReference": "SNAPSCAN 20150109",
        "authCode": "123456",
        "extra": null,
      }
    ]
    

    If the period contains any pending payments you can expect the following response:

    HTTP/1.1 500 INTERNAL SERVER ERRROR
    Content-Type: application/json
    
    {
      "message": "The query is not ready yet because the specified cash up period contains pending payments, please try again in a moment."
    }
    

    Returns all payments that were completed successfully in the specified cash up period. If a cash up period contains any pending payments we will return a HTTP 500. A cash up period is considered complete once we know the status of all the payments within the period. When we return a HTTP 500 due to pending payments you should wait a couple of seconds and then retry the request. See Cash Ups for further details.

    HTTP Request

    GET https://pos.snapscan.io/merchant/api/v1/payments/cash_ups/{reference}

    Route Parameters

    The reference route parameter is required.

    Parameter Description
    reference The cash up period's reference.

    Response Codes

    Description HTTP Status JSON Response
    OK 200 Array of payment objects
    Reference doesn't exist 404 Object containing a message key
    Pending payments 500 Object containing a message key

    Cash Ups

    The cash up API allows you to mark the end of your transaction period on our system. Once a transaction period has been marked you will be able to query all payments that were completed within the associated period. You can use the period's reference with the get cash up payments endpoint to retrieve the payments.

    The cash up object

    An example of a cash up object:

    {
      "date": "1999-12-31T23:00:00Z",
      "reference": "ab34Def78"
    }
    
    Attribute Type Description
    date String The UTC date of when the transaction period was ended. The date is ISO8601 formatted, eg: 1999-12-31T23:00:00Z
    reference String A hexadecimal string with a maximum length of 32.

    Create a cash up period

    curl -u your-api-key: -X POST "https://pos.snapscan.io/merchant/api/v1/cash_ups"
    

    The above command returns JSON structured like this:

    HTTP/1.1 200 OK
    Content-Type: application/json
    
    {
      "date": "1999-12-31T23:00:00Z",
      "reference": "1e07ac748d2627ba"
    }
    

    Returns a reference that marks the end of the current transaction period and the start of a new one. The reference can be used to retrieve all the payments that were successfully completed in the associated period.

    HTTP Request

    POST https://pos.snapscan.io/merchant/api/v1/cash_ups

    Response Codes

    Description HTTP Status JSON Response
    OK 200 A cash up object

    Get all cash ups

    curl -u your-api-key: "https://pos.snapscan.io/merchant/api/v1/cash_ups"
    

    The above command returns JSON structured like this:

    HTTP/1.1 200 OK
    Content-Type: application/json
    
    [
      {
        "date": "2000-01-01T12:00:00Z",
        "reference": "2f35cdc8246915c3"
      },
      {
        "date": "1999-12-31T23:00:00Z",
        "reference": "1e07ac748d2627ba"
      }
    ]
    

    Returns a paginated list of all cash up references that have been created. The references are ordered by descending date.

    HTTP Request

    GET https://pos.snapscan.io/merchant/api/v1/cash_ups

    Response Codes

    Description HTTP Status JSON Response
    OK 200 An array of cash up objects

    Code Snippets

    Javascript

    An example of fetching all payments in Javascript.

    let url = "https://pos.snapscan.io/merchant/api/v1/payments";
    let apiKey = "your-api-key";
    
    let headers = new Headers();
    headers.append("Content-Type", "application/json");
    headers.append("Authorization", `Basic ${btoa(apiKey + ":")}`);
    
    fetch(url, {method: "GET", headers: headers})
      .then(response => response.json())
      .then(data => console.log(data));
    

    Ruby

    An example of fetching all payments in Ruby.

    require "net/http"
    require "openssl"
    
    url = "https://pos.snapscan.io/merchant/api/v1/payments"
    api_key =  "your-api-key"
    
    uri = URI(url)
    
    Net::HTTP.start(uri.host, uri.port,
      :use_ssl => uri.scheme == "https", 
      :verify_mode => OpenSSL::SSL::VERIFY_PEER) do |http|
        request = Net::HTTP::Get.new uri.request_uri
        request.basic_auth api_key, ""
        response = http.request request
        puts response
        puts response.body
      end
    end
    

    Python

    An example of fetching all payments in Python. This example assumes you have installed the requests module.

    import json
    
    import requests
    from requests.auth import HTTPBasicAuth
    
    URL = "https://pos.snapscan.io/merchant/api/v1/payments"
    API_KEY = "your-api-key"
    response = requests.get(URL, auth = HTTPBasicAuth(API_KEY, ""))
    
    print(response.status_code)
    print(json.loads(response.content))
    

    PHP

    An example of fetching all payments in PHP. This example does not illustrate transforming the response into JSON since this is dependent on the module that you have installed in your project. You can also use the built-in json_decode method for this purpose.

    <?PHP
    
    $url = "https://pos.snapscan.io/merchant/api/v1/payments";
    $api_key = "your-api-key";
    
    $opts = array(
      "http" => array(
        "method" => "GET",
        "header" => "Authorization: Basic " . base64_encode("$api_key:")                 
      )
    );
    
    $context = stream_context_create($opts);
    $file = file_get_contents($url, false, $context);
    print($file);
    
    ?>
    

    C#

    An example of fetching all payments in C#. This example does not illustrate transforming the response into JSON since this is dependent on the library that you have installed in your project.

    using System;
    using System.Net;
    
    namespace Snapscan
    {
      class Example
      {
        static void Main(string[] args)
        {
          const String apiKey = "your-api-key";
          const String url = "https://pos.snapscan.io/merchant/api/v1/payments";  
          var client = new WebClient { Credentials = new NetworkCredential(apiKey, "") };
          var response = client.DownloadString(url);
          System.Console.WriteLine(response);
        }
      }
    }
    

    Java

    An example of fetching all payments in Java. This example does not illustrate transforming the response into JSON since this is dependent on the library that you have installed in your project.

    import java.io.BufferedReader;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.util.Base64;
    
    ...
    
    String apiKey = "your-api-key";
    URL url = new URL ("https://pos.snapscan.io/merchant/api/v1/payments");
    String encoding = Base64.getEncoder().encodeToString((apiKey + ":").getBytes("UTF-8"));
    
    HttpURLConnection connection = (HttpURLConnection)url.openConnection();
    connection.setRequestMethod("GET");
    connection.setDoOutput(true);
    connection.setRequestProperty("Authorization", "Basic " + encoding);
    InputStream content = (InputStream)connection.getInputStream();
    StringBuilder sb = new StringBuilder();
    BufferedReader in = new BufferedReader(new InputStreamReader(content));
    
    String line;
    while ((line = in.readLine()) != null)
      sb.append(line);
    
    System.out.println(sb);