Merchant Account at RelayPay

This is a guide for merchants integrating with RelayPay as a payment processor.

Before starting you need to visit the Merchant Dashboard found at https://sandbox-commerce.relaypay.io and create an account.

This is the admin dashboard you can use to see transactions and update any settings associated with your account. Here you will also receive private and public keys to be used for API requests.

Once you complete you profile we’ll need to activate your account.

Sandbox environment

The API Base url for the sandbox environment is api.sandbox.relaypay.io

Sandbox environment is intended for development of an integration and testing purposes. Transactions on sandbox do not require real money nor crypto currency to test. See testing.

Production environment

API base url is for the production environment is api.relaypay.io

In order to use the production environment, as mentioned earlier, you’ll need to open an account at https://commerce.relaypay.io

Overview of Flow

API Methods

All requests to the RelayPay API must be standard HTTPs GET or POST requests. The HTTPs protocol provides a secure means of verifying the program on the client host. Plain text HTTP requests are forbidden, and if the client sends an HTTP request to the server it will be denied.

Create transaction

Request

Post request to:

/api/v1/ecommerce/request

Requests should be signed.

ParameterRequiredExampleDescription
amountyes42.87
customerNameyesJacob
customerEmailyes[email protected]
storeNameyesStore24
merchantIdyes[email protected]merchant email (login)
currencyyesAUD
orderIdyes12345Id generated on the merchant side. Will be returned in webhook payload.
callbackUrlRedirectno<https://yourwebsite.example.com/transaction/status>Where to redirect once the payment is pending (or cancelled if callbackCancelUrlRedirect is blank).
If this value is provided, it will override the fallback option provided in the general settings accessed through the merchant dashboard.
callbackCancelUrlRedirectno<https://yourwebsite.example.com/cancel>Where to redirect once the payment is cancelled. Defaults to callbackUrlRedirect if not provided
webHookUrlno<https://yourwebsite.example.com/api/tx-update>Where to post updates about a payment. These will be posted with every payment change. This callback is guaranteed to happen before we redirect the user back.
If this value is provided, it will override the fallback option provided in the general settings accessed through the merchant dashboard.
Setting this value in the general settings is also optional. If neither place is filled in then the webhook will not be sent.
securityTokennoBasic dXNlcjpwYXNzd29yZA==This token will be sent back with the callback in Authorization header.
(Authorization: [type] [credentials])
When creating the token, both 'type' and 'credentials' are required.
Header NameRequiredExampleDescription
Signyes44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8aSHA 256 of stringify payload + private key

Response

Status 200: redirect url

Status 401: Unauthorised Request Check your public and private keys, check signing process.

Transactions status updates

Webhook

Webhook will be send to webHookUrl which was provided in the create transaction request step.

Webhook Sign header should be verified on the merchant side with private key.

Webhook Authorization header should be verified on the merchant side (if used).

Webhook will be sent once for every status update.

Merchant should respond with status OK (200). If RelayPay does not receive status OK - it will retry sending the webhook every 1 minute until status OK is received for a total of 5 retries.

Webhook payload example:

{
  "orderId": "12345",
  "transactionId": "advgjq-1ba7ak-asdhja8",
  "orderStatus": "Success",
  "customerEmail": "[email protected]",
  "customerName": "John Doe",
  "amount": 42.05
}

Header Sign = dbda6873028004858d93d93bc4c7e751019cf4aad0577922d119ed69f5553650

Header Authorisation = Basic dXNlcjpwYXNzd29yZA==

Possible statuses:

  • Cancelled - cancelled by customer
  • Success - transaction successfully completed
  • Failed - transaction failed
  • Pending - transaction not completed yet.
  • Expired - transaction not completed yet.

Get transactions list

/api/v1/merchant/transaction/history

Method: GET

Header: Authorization - public key

Params:

  • merchantId - merchant email (login)
  • page - number of page
  • size - amount of the elements on the page

Response example:

{
  "totalPages": 0,
  "totalElements": 0,
  "size": 0,
  "content": [
    {
      "orderId": "12345",
      "transactionId": "advgjq-1ba7ak-asdhja8",
      "orderStatus": "Cancelled",
      "customerEmail": "[email protected]",
      "customerName": "John Doe",
      "currency": "AUD",
      "amount": 42.05
    }
  ],
  "number": 0,
  "sort": {
    "unsorted": true,
    "sorted": true,
    "empty": true
  },
  "numberOfElements": 0,
  "first": true,
  "last": true,
  "pageable": {
    "offset": 0,
    "sort": {
      "unsorted": true,
      "sorted": true,
      "empty": true
    },
    "paged": true,
    "unpaged": true,
    "pageNumber": 0,
    "pageSize": 0
  },
  "empty": true
}

Get merchant transaction

/api/v1/merchant/transaction

Method: GET

Header: Authorization - public key

Params:

  • merchantId - merchant email (login)
  • orderId - unique merchant orderId

Response example:

{
  "orderId": "12345",
  "transactionId": "advgjq-1ba7ak-asdhja8",
  "orderStatus": "Success",
  "customerEmail": "[email protected]",
  "customerName": "John Doe",
  "currency": "AUD",
  "amount": 42.05
}

Possible statuses:

  • Cancelled - cancelled by customer
  • Success - transaction successfully completed
  • Failed - transaction failed
  • Pending - transaction not completed yet.

Sign header

Authenticated requests should be signed with Sign header, using a signature generated with SHA 256 of stringified JSON payload and private key according to:

SHA256(stringified JSON payload + privateKey)

Example Sign

Below is a specific example of a sign generated with a particular stringified JSON payload and private key. The request payload used for generating sign and sending API request should be identical to avoid any issue because same payload with different whitespace can generate entirely different signature. Code snippets for generating the sign in Node.js, Python and Java are shown below:

FieldValue
Private (Secret) KeyDOSsQcRP9NnzFJxVQL4W
Stringified JSON Payload{"orderId":"12345","transactionId":"advgjq-1ba7ak-asdhja8","orderStatus":"Success"}
Concat the json String and secret key String{"orderId":"12345","transactionId":"advgjq-1ba7ak-asdhja8","orderStatus":"Success"}DOSsQcRP9NnzFJxVQL4W
The UTF-8 String converted to byte array[123, 34, 111, 114, 100, 101, 114, 73, 100, 34, 58, 34, 49, 50, 51, 52, 53, 34, 44, 34, 116, 114, 97, 110, 115, 97, 99, 116, 105, 111, 110, 73, 100, 34, 58, 34, 97, 100, 118, 103, 106, 113, 45, 49, 98, 97, 55, 97, 107, 45, 97, 115, 100, 104, 106, 97, 56, 34, 44, 34, 111, 114, 100, 101, 114, 83, 116, 97, 116, 117, 115, 34, 58, 34, 83, 117, 99, 99, 101, 115, 115, 34, 125, 68, 79, 83, 115, 81, 99, 82, 80, 57, 78, 110, 122, 70, 74, 120, 86, 81, 76, 52, 87]
Calculate the SHA-256 digest from the byte array and return the value as a byte array.[106, -64, 126, -38, -12, -28, -85, -9, -84, -94, -116, 6, -67, 38, 32, -67, 35, 35, 42, 111, 76, 90, 44, 79, -51, 50, -118, -25, 42, -66, -8, -2]
Convert an array of bytes into an array of characters representing the hexadecimal values of each byte in order in lower case. That's your Sign value6ac07edaf4e4abf7aca28c06bd2620bd23232a6f4c5a2c4fcd328ae72abef8fe

Code Examples

Node.js

const crypto = require('crypto');
 
const getSign = (stringifiedPayload, privateKey) => {
    const hash = new crypto.createHash('sha256');
    return hash.update(stringifiedPayload + privateKey).digest('hex');
};
 
console.log(getSign('{"orderId":"12345","transactionId":"advgjq-1ba7ak-asdhja8","orderStatus":"Success"}', "DOSsQcRP9NnzFJxVQL4W"));

Python

import hashlib
 
def get_sign(stringifiedPayload, privateKey):
    valueToHash = stringifiedPayload + privateKey
    return hashlib.sha256(valueToHash.encode()).hexdigest()
     
     
print(get_sign('{"orderId": "12345", "transactionId": "advgjq-1ba7ak-asdhja8", "orderStatus": "Success"}', 'DOSsQcRP9NnzFJxVQL4W'));

Java

public String getSign(String stringifiedPayload, String privateKey) {
    // Use org.apache.commons.codec.digest.DigestUtils
    return DigestUtils.sha256Hex(stringifiedPayload + privateKey);
}
 
System.out.println(getSign("{\"orderId\": \"12345\", \"transactionId\": \"advgjq-1ba7ak-asdhja8\", \"orderStatus\": \"Success\"}", "DOSsQcRP9NnzFJxVQL4W"));

Verify webhook

RelayPay will send you webhook call with status updates. Request contains header Sign.

To verify authenticity and be sure that request was send from RelayPay you should take stringified request’s payload, concatenate private key and take SHA-256 hash from it. Then just compare result with the value of Sign header from request.

Another header sent is Authorization if there was a securityToken provided with the transaction request.

Testing

By default you will receive Pending and then Complete transaction status.

For testing your backend, you can induce the following responses by sending the following customerEmail on the first step:

CustomerEmailCreate tx responseTx status
[email protected]Status 200Cancelled
[email protected]Status 200Pending → Failed
[email protected]Status 200Pending → Expired