External Authorisation and Balance

This documentation provides an overview of Shaype’s external balance and external authorization proposition. It outlines how the functionality works and highlights key considerations.

What is External Auth?

External authorisation is a process to enable clients to approve or reject card transactions based on their customers' balances and any other internal checks they perform. In this flow, the Shaype platform handles fraud, limits checks, account and rules, while the client is responsible for verifying their customer's balance.

To ensure accuracy in the authorisation of transactions on Shaype-managed payment channels, there must be a single source of truth for account balances, and in the external auth scenario, the account balance is held on the client’s side.

The API is designed to work in conjunction with other APIs we provide, and OpenAPI tools are available to help generate server implementations.

External Client Authorisation​ Flows

Funds Deposit

Funds Withdrawal

Platform Limit Checks

  • The platform checks various limits on transactions. If any single limit is exceeded, the platform will reject the transaction without performing a balance check on the client’s side.
  • The following limits are checked on transactions:
    • ATM_WITHDRAWAL_PER_DAY​
    • TOP_UP_PER_DAY​
    • CARD_PAYMENTS_DAILY​
    • PAYMENT_TO_ACCOUNT_NUMBER​
    • SINGLE_CARD_TRANSACTION​
    • TOTAL_SPEND_PER_YEAR​

APIs

Authorise a Card Hold - POST /hold

  • This endpoint sends a request for the client to authorise or reject the transaction. The client can then either approve the transaction or reject it with an appropriate error code.

API Reference: Authorised a new card hold


Update a Hold Amount - PATCH /holds/{holdId}

  • This endpoint would be used to increase an existing hold amount.

API Reference: Increase an existing hold amount


Authorise a Transaction - POST /transactions

  • This endpoint would authorise a new transaction

API Reference: Authorise a new transaction


Response codes

Shaype requests clients to use specific response codes to indicate the outcome of hold or transaction authorizations. For a successful transaction authorisation, return a 200 OK. In the case of a failure or transaction rejection, the following outcomes must be addressed by the client with a 470 HTTP status code:

📘

Currently, only the following two error codes are supported, any other response sent by the client will default to an outcome of INTERNAL_ERROR

  • REFUSED_MAX_BALANCE_EXCEEDED
  • REFUSED_NOT_ENOUGH_FUNDS

Security

Network level

HTTP-over-TLS (HTTPS) RFC2818 MUST be used for the connection.

List the IP addresses requests will be coming from. Allows the consumer to hide endpoints from the rest of the internet and avoid random scanning and probing as well as targeted attacks.

Application level

Asymmetric Key Signature. This consists of splitting a secret key into a private and public part. The private key will remain with the sender (Shaype) and will be used to sign the body of the request. The signature will be added in the headers of the request. The public key is shared with the receiver, who will use this public keys to run a verifier and check that the signature is valid.

This offers message integrity checks which a simple token doesn’t. Asymmetric keys also offers non-repudiation, it cannot be denied that it came from the sender as only they have the private key.

  • Shaype will use SHA256WithRSA signature algorithm with 2048 bits as it offers high security and fast signature.
  • A key id will be provided from Shaype in the request as a header, this can be used to retrieve the public key from our Authentication API.
  • The public key can be used to verify the signature in the request.

Sample response of endpoint to retrieve public keys:

{
  "keys": [
    {
      "kty": "RSA",
      "alg": "RS256",
      "kid": "HCm7EWcCmpCgXFKTksFSNEx7axjn_FuutbnfKyy-69o",
      "use": "sig",
      "e": "AQAB",
      "n": "abcdefghijklmnopqrstuvwxyzx4885U8770YwRvf6NM3qM4kroGUhPbfqyocPs6rjtYO5BbhJQvVWOHb4XrUb8ZK-F4CfAHU4hDXEbgSoZQjAbFVBeprks5wCwKpWHsxF9K00e4HhsuqwlHEOcbZXZG5mmCNJSZNtIqoC1a1KFij7HqjHxwR7uQjlEq0jH_eDue0rdlaI9UxYE9IQxYKr1QLPkd39o4URPLNMkHbNzXy90gMEF43jIVfWBFDMQ--SrbtvHMC2HN10NeHTc2iH_6nGxzfMMDuQKpRavOsVGp_7RcWtDBRbWdkIeY9StncmK2XnA_GzCajxII7sV6-w"
    }
  ]
}

Example Code Implementation:

//Create transaction json  
Transaction transaction = new Transaction()  
        .transactionId(UUID.randomUUID().toString())  
        .accountId(UUID.randomUUID().toString())  
        .amount(new CurrencyAmount().amount("12345").currency("AED"));

String transactionStr = new ObjectMapper().writeValueAsString(transaction);

//Verify signature  
Signature publicSignature = Signature.getInstance("SHA256withRSA");  
publicSignature.initVerify(keyPair.getPublic());  
publicSignature.update(transactionStr.getBytes(UTF_8));  
byte\[] signatureBytes = Base64.getDecoder().decode(signatureFromRequest);  
boolean verify = publicSignature.verify(signatureBytes);

Replay prevention

Each request comes with unique idempotency key. If the same request is retried it will have the same idempotency key. Idempotency key is part of the message signature. Client is advised to implement idempotent API, that means to ensure the message with the same idempotency key is processed only once.

If client is unable to implement idempotent API, then there is another option. Each request comes with the timestamp. Timestamp is part of the message signature. Timestamp allows client to define acceptable timeframe in which requests must be processed (i.e., 3-5 seconds). If request comes outside of acceptable window, then it’s ignored. For this approach to work client has to ensure server clocks are not skewed.

Notification

You will receive different notification on various transaction outcome

Transaction TypeWhen you will receive the notification?
CARD_TRANSACTION- New hold - Hold Increase - Transactions without holds
CARD_TRANSACTION_SETTLED- After Hold accepted
CARD_TRANSACTION_REFUND- Hold decrease - OCT - Reversal - Refund

📘

  • In the transactionEvent object, we also have the fields accountBalances and updatedBalance, which we won’t be able to populate.
  • For authorisation holds, the isPending flag is set to true, while for settled transactions, it is set to false.

Non-functional Requirements

  • Requests per second (RPS) - 10

Latency:

  • We are given 1.5 seconds by GPS to respond to external balance client authorisation requests
  • 0.4 seconds is the roundtrip between London (our processing centre) and Sydney
  • 0.2 seconds our processing time
  • 0.4 is a buffer (reserved time)
  • 0.5 seconds for Client to reply. Doesn’t include network roundtrip of 0.4 seconds mentioned above

Request to client authorisation API

  • connection timeout 0.4 second
  • request timeout 0.5 second (time after establishing the connection)
  • total request timeout is 0.9 seconds including both establishing the connection and receiving the response