NAV
shell python javascript

Introduction

Zotapay MG Payout API enables Zotapay merchants to:

Before You Begin

In order to use this API, a merchant must first receive from Zotapay the following:

Name Description
MerchantID A merchant unique identifier, used for identification.
MerchantSecretKey A secret key to keep privately and securely, used for authentication.
EndpointID One or more unique endpoint identifiers to use in API requests.

API URL

URL Description
https://api.zotapay-sandbox.com Sandbox environment, used for integration and testing purposes.
https://api.zotapay.com or https://mg-api.zotapay.com Live environment.

Payout Flow

Payout Integration

The merchant must initiate the transaction by sending an HTTP POST Payout Request to the specified endpoint URL.

If the request format is correct, Zotapay's response to this request will contain the parameter orderID, which represents the order number assigned by Zotapay system to that specific payout order.

For more information on the request and response formats for payouts, please refer to the sections below.

Merchant may issue Order Status Requests to retrieve the transaction status.

After the transaction has been successfully processed, Zotapay server will initiate a final HTTP POST request to the callbackUrl specified by the merchant in the Payout Request.

This request will include the transaction final status, along with detailed information about the order.

Payout Form Integration

The merchant must initiate the transaction by sending an HTTP POST Payout Request to the specified endpoint URL.

If the request format is correct, Zotapay's response to this request will contain the parameter orderID, which represents the order number assigned by Zotapay system to that specific payout order alongside the parameter payoutURL, which contains the url of the payout form to be filled out by the end-user.

The merchant server must redirect the waiting end-user to the payoutUrl via HTTP 302 redirection.

The end-user fills out the payout form and submits it.

For more information on the request and response formats for payouts, please refer to the sections below.

Merchant may issue Order Status Requests to retrieve the transaction status.

After the transaction has been successfully processed, Zotapay server will initiate a final HTTP POST request to the callbackUrl specified by the merchant in the Payout Request.

This request will include the transaction final status, along with detailed information about the order.

Please refer to the sections below for detailed information regarding of the steps above.

Authentication

In order for Zotapay server to trust a merchant server, every request should be authenticated.

The authentication process is done using a SHA-256 checksum on critical request parameters, aka signature.

Under each of the sections below you'll find the appropriate Signature section that explains how to generate (or verify) a signature for a specific case.

Example of a SHA-256 signature: b549bdaa4b7ae8d779bdd796190e93f487b2690e7609c5869c4793900cf24a3c

Merchants may find this tool very helpful for signature testing and debugging, with a dedicated section for each of the signing use-cases.

Merchant Endpoints

The EndpointID represents the API destination that each payout request must be submitted to. By design, each endpoint supports only one specific currency.

Once your merchant application is approved by Zotapay, you will be provided with a full list of endpoints for your account, specific to the solution(s) requested.

Payout Request

Context

The payout flow begins when a request to disburse funds is either initiated directly by the merchant server or triggered by the end-user through the merchant's website.

The merchant server should then send a signed Payout Request to the Zotapay server and either expect a response via Callback or poll for status using Order Status Requests.

Issue a Payout Request

Initiates the payout process.

HTTP Request

POST /api/v1/payout/request/EndpointID/

Content-Type: application/json

Merchant -> Zotapay

Request Parameters

Payout Request example

curl -X POST \
    "https://api.zotapay.com/api/v1/payout/request/1050/" \
    -H "Content-Type: application/json" \
    -d '{
        "merchantOrderID": "TbbQzewLWwDW6goc",
        "merchantOrderDesc": "Test order",
        "orderAmount": "500.00",
        "orderCurrency": "THB",
        "customerEmail": "[email protected]",
        "customerFirstName": "John",
        "customerLastName": "Doe",
        "customerPhone": "+66-77999110",
        "customerIP": "103.106.8.104",
        "callbackUrl": "https://www.example-merchant.com/payout-callback/",
        "customerBankCode": "BBL",
        "customerBankAccountNumber": "100200",
        "customerBankAccountName": "John Doe",
        "customerBankBranch": "Bank Branch",
        "customerBankAddress": "Thong Nai Pan Noi Beach, Baan Tai, Koh Phangan",
        "customerBankZipCode": "84280",
        "customerBankProvince": "Bank Province",
        "customerBankArea": "Bank Area / City",
        "customerBankRoutingNumber": "000",
        "customParam": "{\"UserId\": \"e139b447\"}",
        "checkoutUrl": "https://www.example-merchant.com/account/withdrawal/?uid=e139b447",
        "signature": "d04ccb6a14d2c9e6f566766b8158bc4dd5ab6c3bb964a446da92aa61b882d88b"
    }'
import requests  # pip install requests

url = 'https://api.zotapay.com/api/v1/payout/request/1050/'
payload = {
    "merchantOrderID": "TbbQzewLWwDW6goc",
    "merchantOrderDesc": "Test order",
    "orderAmount": "500.00",
    "orderCurrency": "THB",
    "customerEmail": "[email protected]",
    "customerFirstName": "John",
    "customerLastName": "Doe",
    "customerPhone": "+66-77999110",
    "customerIP": "103.106.8.104",
    "callbackUrl": "https://www.example-merchant.com/payout-callback/",
    "customerBankCode": "BBL",
    "customerBankAccountNumber": "100200",
    "customerBankAccountName": "John Doe",
    "customerBankBranch": "Bank Branch",
    "customerBankAddress": "Thong Nai Pan Noi Beach, Baan Tai, Koh Phangan",
    "customerBankZipCode": "84280",
    "customerBankProvince": "Bank Province",
    "customerBankArea": "Bank Area / City",
    "customerBankRoutingNumber": "000",
    "customParam": "{\"UserId\": \"e139b447\"}",
    "checkoutUrl": "https://www.example-merchant.com/account/withdrawal/?uid=e139b447",
    "signature": "d04ccb6a14d2c9e6f566766b8158bc4dd5ab6c3bb964a446da92aa61b882d88b"
}
headers = {'content-type': 'application/json'}

try:
  response = requests.post(url, json=payload, headers=headers)
except Exception as e:
  raise Exception(f"payout request failed, error: {e}")

print( response.json() )  # {'code': '200', 'data': { ... }}

const request = require('request'); // npm install request

const opts = {
  uri: 'https://api.zotapay.com/api/v1/payout/request/1050/',
  method: 'POST',
  json: {
    "merchantOrderID": "TbbQzewLWwDW6goc",
    "merchantOrderDesc": "Test order",
    "orderAmount": "500.00",
    "orderCurrency": "THB",
    "customerEmail": "[email protected]",
    "customerFirstName": "John",
    "customerLastName": "Doe",
    "customerPhone": "+66-77999110",
    "customerIP": "103.106.8.104",
    "callbackUrl": "https://www.example-merchant.com/payout-callback/",
    "customerBankCode": "BBL",
    "customerBankAccountNumber": "100200",
    "customerBankAccountName": "John Doe",
    "customerBankBranch": "Bank Branch",
    "customerBankAddress": "Thong Nai Pan Noi Beach, Baan Tai, Koh Phangan",
    "customerBankZipCode": "84280",
    "customerBankProvince": "Bank Province",
    "customerBankArea": "Bank Area / City",
    "customerBankRoutingNumber": "000",
    "customParam": "{\"UserId\": \"e139b447\"}",
    "checkoutUrl": "https://www.example-merchant.com/account/withdrawal/?uid=e139b447",
    "signature": "55814f758c27cf3171c332e0b879dec36bed946f4e93a0eeb381842e84423629"
  }
};

request(opts, function (error, response, body) {
  if (error || response.statusCode !== 200) {
    console.log('request got an error:');
    console.log(body);
    return
  }

  console.log('request got OK');
  console.log(body);
  // {code: '200', data: { ... }}
});
Name Max. Length Description Required
merchantOrderID 128 Merchant-defined unique order identifier Yes
merchantOrderDesc 128 Brief order description Yes
orderAmount 24 Amount to be charged, must be specified with delimiter, e.g. 1.50 for USD is 1 dollar and 50 cents Yes
orderCurrency 3 Currency to be charged in, three-letter ISO 4217 currency code. See Currency Codes for a full list of currency codes. Yes
customerEmail 50 End user email address Conditional
customerFirstName 128 End user first name Conditional
customerLastName 128 End user last name Conditional
customerPhone 15 End user full international telephone number, including country code Conditional
customerIP 64 End user IPv4/IPv6 address Conditional
customerPersonalID 20 End user personal ID number Conditional
customerBankCode 11 End user bank code Conditional
customerBankAccountNumber 64 End user bank account number Yes
customerBankAccountNumberDigit 2 End user bank account number control digit Conditional
customerBankAccountType 8 End user bank account type, either checking or savings Conditional
customerBankSwiftCode 35 End user bank swift code Conditional
customerBankAccountName 128 End user bank account name Yes
customerBankBranch 128 End user bank branch name Conditional
customerBankBranchDigit 2 End user bank branch control digit Conditional
customerBankAddress 128 End user bank address Conditional
customerBankZipCode 15 End user bank postal code Conditional
customerBankRoutingNumber 16 Routing number used to identify specific bank branches in China Conditional
customerBankProvince 64 End user bank province No
customerBankArea 64 End user bank area / city No
callbackUrl 255 URL the order status will be sent to, see Callback section below for more details No
customParam 128 Merchant-defined optional custom parameter No
signature 64 Request checksum encrypted with SHA-256, see Signature section below for more details Yes

A successful response from Zotapay server to the example request above:

{
    "code": "200",
    "data": {
        "merchantOrderID": "TbbQzewLWwDW6goc",
        "orderID": "beb3e2e1cf59b0d275984ceaf58cd7f7b4b5b09a"
    }
}

A non-successful response from Zotapay server to the example request above:

{
    "code": "401",
    "message": "unauthorized"
}

Or alternatively

{
    "code": "400",
    "message": "endpoint currency mismatch"
}

See Error Codes for a full list of codes.

HTTP Response

Content-Type: application/json

Zotapay -> Merchant

Name Description
code A status code representing the acceptance of the request by Zotapay server.
message When code is other than 200, this parameter may hold information about the reason / error.
data When code is 200, this parameter will include the following fields: merchantOrderID and orderID. Please see the table below for detailed information regarding these fields.

The data Response Parameter

Field Description
merchantOrderID Merchants' order unique identifier, provided in the original Payout Request or Payout Form Request.
orderID Order unique identifier generated by Zotapay, should be then used for Order Status Requests.

Payout Form Integration

In case the merchant does not have or wishes to collect payout recipient information directly from the end-user, the request parameters should be sent as follows:

Name Max. Length Description Required
merchantOrderID 128 Merchant-defined unique order identifier Yes
merchantOrderDesc 128 Brief order description Yes
orderAmount 24 Amount to be charged, must be specified with delimiter, e.g. 1.50 for USD is 1 dollar and 50 cents Yes
orderCurrency 3 Currency to be charged in, three-letter ISO 4217 currency code. See Currency Codes for a full list of currency codes. Yes
customerEmail 50 End user email address Conditional
customerFirstName 128 End user first name Conditional
customerLastName 128 End user last name Conditional
customerPhone 15 End user full international telephone number, including country code Conditional
customerIP 64 End user IPv4/IPv6 address Conditional
customerBankCode 11 End user bank code
Parameter may not be empty; send "none" to display field in payout form
Yes
customerBankAccountNumber 64 End user bank account number
Parameter may not be empty; send "none" to display field in payout form
Yes
customerBankAccountName 128 End user bank account name
Parameter may not be empty; send "none" to display field in payout form
Yes
customerBankBranch 128 End user bank branch name Conditional
customerBankAddress 128 End user bank address Conditional
customerBankZipCode 15 End user bank postal code Conditional
customerBankRoutingNumber 16 Routing number used to identify specific bank branches in China Conditional
customerBankProvince 64 End user bank province Conditional
customerBankArea 64 End user bank area / city Conditional
callbackUrl 255 URL the order status will be sent to, see Callback section below for more details Conditional
redirectUrl 255 URL for end user redirection upon transaction completion, regardless of order status, see Final Redirection section below for more details Yes
customParam 128 Merchant-defined optional custom parameter Conditional
signature 64 Request checksum encrypted with SHA-256, see Signature section below for more details Yes

HTTP Response (Payout Form Integration)

Content-Type: application/json

Zotapay -> Merchant

Name Description
code A status code representing the acceptance of the request by Zotapay server.
message When code is other than 200, this parameter may hold information about the reason / error.
data When code is 200, this parameter will include the following fields: merchantOrderID, orderID and payoutUrl. Please see the table below for detailed information regarding these fields.

The data Response Parameter

Fields Description
merchantOrderID Merchants' order unique identifier, provided in the original Payout Request or Payout Form Request.
orderID Order unique identifier generated by Zotapay, should be then used for Order Status Requests.
payoutUrl The URL of the payout form, merchant should redirect the (waiting) end-user to this URL (HTTP 302).

Signature

Every request must be signed by the merchant in order to be successfully authenticated by Zotapay servers.

The signature parameter of a Payout Request or Payout Form Request must be generated by hashing a string of concatenated parameters using SHA-256 in the exact following order:

EndpointID + merchantOrderID + orderAmount + customerEmail + customerBankAccountNumber + MerchantSecretKey

Signing a Payout Request


# prepare vars
endpointID=1050
merchantOrderID=QvE8dZshpKhaOmHY
orderAmount=500.00
customerEmail=[email protected]
bankAccNum=100200
secretKey=EXAMPLE-SECRET-KEY

# concatenate values into a single string
str="${endpointID}${merchantOrderID}${orderAmount}${customerEmail}${bankAccNum}${secretKey}"
echo $str
# [email protected]E-SECRET-KEY

# create a sha256 hash of the string
sig=$(echo -n "${str}" | openssl dgst -sha256)
echo $sig
# 55814f758c27cf3171c332e0b879dec36bed946f4e93a0eeb381842e84423629

from hashlib import sha256

# prepare vars
endpoint = "1050"
moid = "QvE8dZshpKhaOmHY"
amt = "500.00"
email = "[email protected]"
acc_num = "100200"
secret = "EXAMPLE-SECRET-KEY"

# concatenate values into a single string
s = f"{endpoint}{moid}{amt}{email}{acc_num}{secret}"

# create a sha256 hash of the string
sig = sha256(s.encode('utf-8')).hexdigest()
print( sig )  # 55814f758c27cf3171c332e0b879dec36bed946f4e93a0eeb381842e84423629
const crypto = require('crypto'); // npm install crypto

const endpoint = "1050";
const moid = "QvE8dZshpKhaOmHY";
const amt = "500.00";
const email = "[email protected]";
const accNum = "100200";
const secret = "EXAMPLE-SECRET-KEY";

const s = endpoint + moid + amt + email + accNum + secret;
const sig = crypto.createHash('sha256').update(s).digest('hex');

console.log(sig); // 55814f758c27cf3171c332e0b879dec36bed946f4e93a0eeb381842e84423629

Order Status Request

Context

Merchant should issue an Order Status Request to get the most up-to-date status of customer’s order transaction.

After a Payout Request is sent to Zotapay server and orderID is returned, merchant server should start polling (10-15 seconds interval).

This polling interval should continue until one of the following occurs:

  1. Zotapay server responds to an Order Status Request with a final status (e.g. APPROVED, DECLINED)

  2. Merchant server receives a callback notification from Zotapay with a final status (e.g. APPROVED, DECLINED)

Issue an Order Status Request

HTTP Request

GET /api/v1/query/order-status/

Merchant -> Zotapay

Query Parameters

Order Status Request example

# prepare vars
mid=EXAMPLE-MERCHANT-ID
moid=TbbQzewLWwDW6goc
oid=beb3e2e1cf59b0d275984ceaf58cd7f7b4b5b09a
ts=1564617600
sig=653105b9423fa0e18857e031e7ee87c3885f2b319a5fe1e191ac6005cdcb4835

# prepare query string
qs="merchantID=${mid}&merchantOrderID=${moid}&orderID=${oid}&timestamp=${ts}&signature=${sig}"

# send request
curl -X GET "https://api.zotapay.com/api/v1/query/order-status/?${qs}"
import requests  # pip install requests

# prepare vars
mid = "EXAMPLE-MERCHANT-ID"
moid = "TbbQzewLWwDW6goc"
oid = "beb3e2e1cf59b0d275984ceaf58cd7f7b4b5b09a"
ts = "1564617600"  # str(int(time.time()))
sig = "653105b9423fa0e18857e031e7ee87c3885f2b319a5fe1e191ac6005cdcb4835"

# prepare query string
qs=f"merchantID={mid}&merchantOrderID={moid}&orderID={oid}&timestamp={ts}&signature={sig}"
url = f"https://api.zotapay.com/api/v1/query/order-status/?{qs}"

# send request
try:
  response = requests.get(url)
except Exception as e:
  raise Exception(f"order status request failed, error: {e}")

print( response.json() )  # {'code': '200', 'data': { ... }}

const request = require('request'); // npm install request

const mid = "EXAMPLE-MERCHANT-ID";
const moid = "TbbQzewLWwDW6goc";
const oid = "beb3e2e1cf59b0d275984ceaf58cd7f7b4b5b09a";
const ts = "1564617600";  // parseInt((new Date().getTime()) / 1000).toString()
const sig = "653105b9423fa0e18857e031e7ee87c3885f2b319a5fe1e191ac6005cdcb4835";

const qs = `merchantID=${mid}&merchantOrderID=${moid}&orderID=${oid}&timestamp=${ts}&signature=${sig}`;
const url = `https://api.zotapay.com/api/v1/query/order-status/?${qs}`;

request(url, function (error, response, body) {
  if (error || response.statusCode !== 200) {
    console.log('request got an error:');
    console.log(body);
    return
  }

  console.log('request got OK');
  console.log(body);
  // {code: '200', data: { ... }}
});
Name Max. Length Description Required
merchantID 32 Unique merchant identifier provided by Zotapay (see Before You Begin section) Yes
orderID 128 Order unique identifier generated by Zotapay Yes
merchantOrderID 128 Merchant-defined unique order identifier Yes
timestamp 15 Unix timestamp of the request time Yes
signature 64 Request checksum encrypted with SHA-256, see Signature section below for more details Yes

HTTP Response

Content-Type: application/json

Zotapay -> Merchant

Name Description
code A status code representing the acceptance of the request by Zotapay server.
message When code is other than 200, this parameter may hold information about the reason / error.
data When code is 200, this parameter will include the following fields: merchantOrderID, orderID and payoutUrl. Please see the table below for detailed information regarding these fields.

The data Response Parameter

A successful response from Zotapay server to the example request above:

{
    "code": "200",
    "data": {
        "type": "PAYOUT",
        "status": "PROCESSING",
        "errorMessage": "",
        "endpointID": "1050",
        "processorTransactionID": "",
        "orderID": "beb3e2e1cf59b0d275984ceaf58cd7f7b4b5b09a",
        "merchantOrderID": "TbbQzewLWwDW6goc",
        "amount": "500.00",
        "currency": "THB",
        "customerEmail": "[email protected]",
        "customParam": "{\"UserId\": \"e139b447\"}",
        "extraData": "",
        "request": {
            "merchantID": "EXAMPLE-MERCHANT-ID",
            "orderID": "beb3e2e1cf59b0d275984ceaf58cd7f7b4b5b09a",
            "merchantOrderID": "TbbQzewLWwDW6goc",
            "timestamp": "1564617600"
        }
    }
}

A non-successful response from Zotapay server to the example request above:

{
    "code": "401",
    "message": "unauthorized"
}

Or alternatively

{
    "code": "400",
    "message": "timestamp too old"
}

See Error Codes for a full list of codes.

Name Description
type Transaction type: PAYOUT.
status Transaction status, see Order Statuses for a full list of statuses.
errorMessage Contains the error description if the transaction is declined or yields an error.
processorTransactionID The transaction identifier that was generated by the payment processor.
orderID Order unique identifier generated by Zotapay.
merchantOrderID Merchant-defined unique order identifier.
amount The amount of the transaction.
currency The currency of the transaction.
customerEmail End-user email address.
customParam Merchant-defined optional custom parameter.
request A Json object with a copy of the original Order Status Request sent by merchant server to Zotapay.

Signature

Every request must be signed by the merchant in order to be successfully authenticated by Zotapay servers. The signature parameter of an Order Status Request must be generated by hashing a string of concatenated parameters using SHA-256 in the exact following order:

MerchantID + merchantOrderID + orderID + timestamp + MerchantSecretKey

Signing an Order Status Request


# prepare vars
merchantID=EXAMPLE-MERCHANT-ID
merchantOrderID=TbbQzewLWwDW6goc
orderID=beb3e2e1cf59b0d275984ceaf58cd7f7b4b5b09a
timestamp=1564617600
secretKey=EXAMPLE-SECRET-KEY

# concatenate values into a single string
str="${merchantID}${merchantOrderID}${orderID}${timestamp}${secretKey}"
echo $str
# EXAMPLE-MERCHANT-IDTbbQzewLWwDW6gocbeb3e2e1cf59b0d275984ceaf58cd7f7b4b5b09a1564617600EXAMPLE-SECRET-KEY

# create a sha256 hash of the string
sig=$(echo -n "${str}" | openssl dgst -sha256)
echo $sig
# 653105b9423fa0e18857e031e7ee87c3885f2b319a5fe1e191ac6005cdcb4835

from hashlib import sha256

# prepare vars
mid = "EXAMPLE-MERCHANT-ID"
moid = "TbbQzewLWwDW6goc"
oid = "beb3e2e1cf59b0d275984ceaf58cd7f7b4b5b09a"
ts = "1564617600"  # str(int(time.time()))
secret = "EXAMPLE-SECRET-KEY"

# concatenate values into a single string
s = f"{mid}{moid}{oid}{ts}{secret}"

# create a sha256 hash of the string
sig = sha256(s.encode('utf-8')).hexdigest()
print( sig )  # 653105b9423fa0e18857e031e7ee87c3885f2b319a5fe1e191ac6005cdcb4835
const crypto = require('crypto'); // npm install crypto

const mid = "EXAMPLE-MERCHANT-ID";
const moid = "TbbQzewLWwDW6goc";
const oid = "beb3e2e1cf59b0d275984ceaf58cd7f7b4b5b09a";
const ts = "1564617600";  // parseInt((new Date().getTime()) / 1000).toString()
const secret = "EXAMPLE-SECRET-KEY";

const s = mid + moid + oid + ts + secret;
const sig = crypto.createHash('sha256').update(s).digest('hex');

console.log(sig); // 653105b9423fa0e18857e031e7ee87c3885f2b319a5fe1e191ac6005cdcb4835

Order Completion

Context

After the transaction has been successfully processed, Zotapay server will initiate a final HTTP POST request to the callbackUrl specified by the merchant in the Payout Request.

This request will include the transaction final status, along with detailed information about the order.

Callback Notification

Callbacks are the most accurate way to record the final status for any given order.

Once a transaction is processed and its status is final (see Order Statuses), Zotapay server will initiate an HTTP POST request to merchant callbackUrl provided in the original Payout Request.

The callback notification request will contain all the relevant parameters identifying a specific order, along with the status parameter representing the final status of the transaction.

This request also includes more useful information about the order and can be seen as kind of a detailed order summary.

HTTP Request

HTTP POST

Content-Type: application/json

ZotaPay -> PayoutRequest.callbackUrl

Request Parameters

Example Callback Notification

{
  "type": "PAYOUT",
  "amount": "500.00",
  "status": "APPROVED",
  "orderID": "beb3e2e1cf59b0d275984ceaf58cd7f7b4b5b09a",
  "currency": "THB",
  "extraData": {
    "ID": "000139825",
    "Note": "Test order",
    "Amount": "500.00",
    "Status": "000",
    "Currency": "THB",
    "Customer": "[email protected]",
    "Datetime": "2019-08-01 09:00:00PM",
    "StatementDate": "2019-08-01 10:10:00PM",
    "selectedBankCode": "BBL",
    "selectedBankName": "Bangkok Bank"
  },
  "signature": "6a27d8baea0e676820ceddb994259619134ece0d2ecaf8c033452d48f947ffa5",
  "endpointID": "1050",
  "customParam": "{\"UserId\": \"e139b447\"}",
  "errorMessage": "",
  "customerEmail": "[email protected]",
  "merchantOrderID": "TbbQzewLWwDW6goc",
  "originalRequest": {
    "merchantOrderID": "TbbQzewLWwDW6goc",
    "merchantOrderDesc": "Test order",
    "orderAmount": "500.00",
    "orderCurrency": "THB",
    "customerEmail": "[email protected]",
    "customerFirstName": "John",
    "customerLastName": "Doe",
    "customerPhone": "+66-77999110",
    "customerIP": "103.106.8.104",
    "callbackUrl": "https://www.example-merchant.com/payout-callback/",
    "customerBankCode": "BBL",
    "customerBankAccountNumber": "100200",
    "customerBankAccountName": "John Doe",
    "customerBankBranch": "Bank Branch",
    "customerBankAddress": "Thong Nai Pan Noi Beach, Baan Tai, Koh Phangan",
    "customerBankZipCode": "84280",
    "customerBankProvince": "Bank Province",
    "customerBankArea": "Bank Area / City",
    "customerBankRoutingNumber": "000",
    "customParam": "{\"UserId\": \"e139b447\"}",
    "checkoutUrl": "https://www.example-merchant.com/account/withdrawal/?uid=e139b447",
    "signature": "d04ccb6a14d2c9e6f566766b8158bc4dd5ab6c3bb964a446da92aa61b882d88b",
    "customerState": "",
    "midDescriptor": "",
    "paymentMethod": ""
  },
  "processorTransactionID": "000139825"
}
Name Description
type Transaction type, either SALE or PAYOUT.
status Transaction status, see Order Statuses for a full list of statuses.
errorMessage Contains the error description if the transaction is declined or yields an error.
endpointID The merchant EndpointID that the order was sent through.
processorTransactionID The transaction identifier that was generated by the payment processor.
orderID Order unique identifier generated by Zotapay.
merchantOrderID Merchant-defined unique order identifier.
amount The amount of the transaction.
currency The currency of the transaction.
customerEmail End-user email address.
customParam Merchant-defined optional custom parameter.
extraData A Json object with additional information that was collected during the payment process on Zotapay's environment, such as paymentMethod (string), selectedBankCode (string), etc.
originalRequest A Json object with a copy of the original Deposit Request sent by merchant server to Zotapay.
signature Request checksum encrypted with SHA-256, see Request Signature section below for more details

Signature

When Zotapay sends an http callback notification to merchant's callbackUrl, this request request includes a signature parameter. The signature parameter must be verified by the merchant. A verification is done by hashing a string of concatenated parameters using SHA-256 in the exact following order:

EndpointID + orderID + merchantOrderID + status + amount + customerEmail + MerchantSecretKey

And then by ensuring that the result is equal to the signature parameter of the request.
If both signatures are equal, you should consider the request as authentic.

Verifying Callback Signature


# prepare vars
endpointID=1050
orderID=beb3e2e1cf59b0d275984ceaf58cd7f7b4b5b09a
merchantOrderID=TbbQzewLWwDW6goc
status=APPROVED
amount=500.00
email=[email protected]
secretKey=EXAMPLE-SECRET-KEY

# concatenate values into a single string
str="${endpointID}${orderID}${merchantOrderID}${status}${amount}${email}${secretKey}"
echo $str
# 1050beb3e2e1cf59b0d[email protected]email-address.comEXAMPLE-SECRET-KEY

# create a sha256 hash of the string
sig=$(echo -n "${str}" | openssl dgst -sha256)
echo $sig
# 6a27d8baea0e676820ceddb994259619134ece0d2ecaf8c033452d48f947ffa5

# if provided 'signature' equals to 'sig', consider the request as authentic.

from hashlib import sha256

# prepare vars
endpoint = "1050"
oid = "beb3e2e1cf59b0d275984ceaf58cd7f7b4b5b09a"
moid = "TbbQzewLWwDW6goc"
status = "APPROVED"
amt = "500.00"
email = "[email protected]"
secret = "EXAMPLE-SECRET-KEY"

# concatenate values into a single string
s = f"{endpoint}{oid}{moid}{status}{amt}{email}{secret}"

# create a sha256 hash of the string
sig = sha256(s.encode('utf-8')).hexdigest()
print( sig )  # 6a27d8baea0e676820ceddb994259619134ece0d2ecaf8c033452d48f947ffa5
const crypto = require('crypto'); // npm install crypto

const endpoint = "1050";
const oid = "beb3e2e1cf59b0d275984ceaf58cd7f7b4b5b09a";
const moid = "TbbQzewLWwDW6goc";
const status = "APPROVED";
const amt = "500.00";
const email = "[email protected]";
const secret = "EXAMPLE-SECRET-KEY";

const s = endpoint + oid + moid + status + amt + email + secret;
const sig = crypto.createHash('sha256').update(s).digest('hex');

console.log(sig); // 6a27d8baea0e676820ceddb994259619134ece0d2ecaf8c033452d48f947ffa5

Orders Report

Context

At any single point in time merchants are able to issue an Orders Report Request in order to receive a detailed transaction log of their account by a given date range.

Issue an Orders Report Request

HTTP Request

GET /api/v1/query/orders-report/csv/

Merchant -> Zotapay

Query Parameters

Orders Report Request example

# prepare vars
mid='EXAMPLE-MERCHANT-ID'
date_type='created'
endpoint_ids='1001,1002'
from_date='2019-11-01'
request_id='d6da50a9-aca4-4d6f-a022-f487a127b54d'
statuses='APPROVED,DECLINED'
ts='1573533000'
to_date='2019-11-01'
types='SALE,PAYOUT'
sig='677ff8f149c7cbe54937312ac5d6f5fc838417ba9a4a04779be2c75edde1d714'

# prepare query string
qs="merchantID=${mid}&dateType=${date_type}&endpointIds=${endpoint_ids}&fromDate=${from_date}&requestID=${request_id}&statuses=${statuses}&timestamp=${ts}&toDate=${to_date}&types=${types}&signature=${sig}"

# send request
curl -X GET "https://api.zotapay.com/api/v1/query/orders-report/csv/?${qs}"
import requests  # pip install requests

# prepare vars
mid = 'EXAMPLE-MERCHANT-ID'
date_type = 'created'
endpoint_ids = '1001,1002'
from_date = '2019-11-01'
request_id = 'd6da50a9-aca4-4d6f-a022-f487a127b54d'
statuses = 'APPROVED,DECLINED'
ts = '1573533000'  # str(int(time.time()))
to_date = '2019-11-01'
types = 'SALE,PAYOUT'
sig='677ff8f149c7cbe54937312ac5d6f5fc838417ba9a4a04779be2c75edde1d714'

# prepare query string
qs=f"merchantID={mid}&dateType={date_type}&endpointIds={endpoint_ids}&fromDate={from_date}&requestID={request_id}&statuses={statuses}&timestamp={ts}&toDate={to_date}&types={types}&signature={sig}"
url = f"https://api.zotapay.com/api/v1/query/orders-report/csv/?{qs}"

# send request
try:
  response = requests.get(url)
except Exception as e:
  raise Exception(f"order status request failed, error: {e}")

print( response.json() )  # {'code': '200', 'data': { ... }}

const request = require('request'); // npm install request

const mid = 'EXAMPLE-MERCHANT-ID'
const date_type = 'created'
const endpoint_ids = '1001,1002'
const from_date = '2019-11-01'
const request_id = 'd6da50a9-aca4-4d6f-a022-f487a127b54d'
const statuses = 'APPROVED,DECLINED'
const ts = '1573533000'  // parseInt((new Date().getTime()) / 1000).toString()
const to_date = '2019-11-01'
const types = 'SALE,PAYOUT'
const sig='677ff8f149c7cbe54937312ac5d6f5fc838417ba9a4a04779be2c75edde1d714'


const qs = `merchantID=${mid}&dateType=${date_type}&endpointIds=${endpoint_ids}&fromDate=${from_date}&requestID=${request_id}&statuses=${statuses}&timestamp=${ts}&toDate=${to_date}&types=${types}&signature=${sig}`;
const url = `https://api.zotapay.com/api/v1/query/orders-report/csv/?${qs}`;

request(url, function (error, response, body) {
  if (error || response.statusCode !== 200) {
    console.log('request got an error:');
    console.log(body);
    return
  }

  console.log('request got OK');
  console.log(body);
  // {code: '200', data: { ... }}
});
Name Max. Length Description Required
merchantID 32 Unique merchant identifier provided by Zotapay (see Before You Begin section) Yes
dateType 8 Set date filter type either as created or ended, related to fromDate and toDate Yes
endpointIds 128 Commas separated list of Endpoint Ids to filter from, e.g 1001,1002,1004 No
fromDate 12 Report starting date, format YYYY-MM-DD, e.g 2019-11-01 Yes
requestID 36 A unique identifier for the request, must be of type uuid4 Yes
statuses 128 Commas separated list of Order Statuses to filter by, e.g APPROVED,DECLINED. see Order Statuses for a full list of statuses. No
timestamp 15 Unix timestamp of the request time Yes
toDate 12 Report ending date, format YYYY-MM-DD, e.g 2019-11-01 Yes
types 128 Commas separated list of Order Types to filter by, supported types are SALE, PAYOUT, TOPUP and SETTLEMENT No
signature 64 Request checksum encrypted with SHA-256, see Signature section below for more details. Yes

HTTP Response

Content-Type: text/csv

Zotapay -> Merchant

Response payload will be returned as a CSV stream of the results.

Signature

Every request must be signed by the merchant in order to be successfully authenticated by Zotapay servers. The signature parameter of an Orders Report Request must be generated by hashing a string of concatenated parameters using SHA-256 in the exact following order:

MerchantID + dateType + endpointIds + fromDate + requestID + statuses + timestamp + toDate + types + MerchantSecretKey

Signing an Orders Report Request


# prepare vars
mid='EXAMPLE-MERCHANT-ID'
date_type='created'
endpoint_ids='1001,1002'
from_date='2019-11-01'
request_id='d6da50a9-aca4-4d6f-a022-f487a127b54d'
statuses='APPROVED,DECLINED'
ts='1573533000'
to_date='2019-11-01'
types='SALE,PAYOUT'
secret='EXAMPLE-SECRET-KEY'

# concatenate values into a single string
str="${mid}${date_type}${endpoint_ids}${from_date}${request_id}${statuses}${ts}${to_date}${types}${secret}"
echo $str
# EXAMPLE-MERCHANT-IDcreated1001,10022019-11-01d6da50a9-aca4-4d6f-a022-f487a127b54dAPPROVED,DECLINED15735330002019-11-01SALE,PAYOUTEXAMPLE-SECRET-KEY

# create a sha256 hash of the string
sig=$(echo -n "${str}" | openssl dgst -sha256)
echo $sig
# 677ff8f149c7cbe54937312ac5d6f5fc838417ba9a4a04779be2c75edde1d714

from hashlib import sha256

# prepare vars
mid = 'EXAMPLE-MERCHANT-ID'
date_type = 'created'
endpoint_ids = '1001,1002'
from_date = '2019-11-01'
request_id = 'd6da50a9-aca4-4d6f-a022-f487a127b54d'
statuses = 'APPROVED,DECLINED'
ts = '1573533000'  # str(int(time.time()))
to_date = '2019-11-01'
types = 'SALE,PAYOUT'
secret = "EXAMPLE-SECRET-KEY"

# concatenate values into a single string
s = f"{mid}{date_type}{endpoint_ids}{from_date}{request_id}{statuses}{ts}{to_date}{types}{secret}"

# create a sha256 hash of the string
sig = sha256(s.encode('utf-8')).hexdigest()
print( sig )  # 677ff8f149c7cbe54937312ac5d6f5fc838417ba9a4a04779be2c75edde1d714
const crypto = require('crypto'); // npm install crypto

const mid = 'EXAMPLE-MERCHANT-ID'
const date_type = 'created'
const endpoint_ids = '1001,1002'
const from_date = '2019-11-01'
const request_id = 'd6da50a9-aca4-4d6f-a022-f487a127b54d'
const statuses = 'APPROVED,DECLINED'
const ts = '1573533000'  // parseInt((new Date().getTime()) / 1000).toString()
const to_date = '2019-11-01'
const types = 'SALE,PAYOUT'
const secret = "EXAMPLE-SECRET-KEY";
const s = mid + date_type + endpoint_ids + from_date + request_id + statuses + ts + to_date + types + secret;
const sig = crypto.createHash('sha256').update(s).digest('hex');

console.log(sig); // 677ff8f149c7cbe54937312ac5d6f5fc838417ba9a4a04779be2c75edde1d714

Error Codes

Context

Every request to Zotapay's API is answered with a response. Every response from Zotapay will be structured as following:

HTTP Response

Content-Type: application/json

Zotapay -> Merchant

Name Description
code A status code representing the acceptance of the request by Zotapay server.
message When code is other than 200, this parameter may hold information about the reason / error.
data When code is 200, this parameter will hold a JSON object with different fields, depending on the requested resource and context.

Response Codes

Code Meaning Common message values
200 OK -
400 Invalid or malformed request bad request, endpoint currency mismatch, missing arguments, expired ...
401 Invalid signature unauthorized
404 Not found not found
409 Conflict order already created, already requested ...
410, 500 Error unresolved, internal error

Signature Helper

Merchants may find this tool very helpful for signature testing and debugging, with a dedicated section for each of the signing use-cases.

Common Resources

Order Statuses

Status Description
CREATED Order was created.
AUTHORIZED Order is accepted and will begin processing shortly.
PROCESSING Order is being processed, continue polling until final status.
APPROVED Order is approved, final status.
DECLINED Order is declined, final status.
FILTERED Order is declined by fraud-prevention system.
PENDING Order is still in processing state, awaiting next step.
UNKNOWN Order status is unknown, please inform our support team. not a final status.
ERROR Order is declined due to a technical error, please inform our support team. final status.

Currency Codes

Code Name
EUR Euro €
USD US Dollar $
BTC Bitcoin ₿
CNY Yuan Renminbi ¥
AFN Afghani ؋
DZD Algerian Dinar دج
ARS Argentine Peso $
AMD Armenian Dram ֏
AWG Aruban Florin ƒ
AUD Australian Dollar $
AZN Azerbaijanian Manat ₼
BSD Bahamian Dollar $
BHD Bahraini Dinar BD
THB Baht ฿
PAB Panamanian Balboa B/
BBD Barbados Dollar Bds$
BYR Belarussian Ruble Br
BZD Belize Dollar $
BMD Bermudian Dollar $
VEF Venezuelan Bolivar Bs
BOB Bolivian Boliviano Bs
BRL Brazilian Real R$
BND Brunei Dollar $
BGN Bulgarian Lev Лв
BIF Burundi Franc FBu
CVE Cabo Verde Escudo Esc
CAD Canadian Dollar $
KYD Cayman Islands Dollar $
XOF CFA Franc BCEAO CFA
XAF CFA Franc BEAC FCFA
XPF CFP Franc ₣
CLP Chilean Peso $
COP Colombian Peso $
KMF Comoro Franc CF
CDF Congolese Franc FC
BAM Convertible Mark KM
NIO Cordoba Oro C$
CRC Costa Rican Colon ₡
CUP Cuban Peso ₱
CZK Czech Koruna Kč
GMD Gambian Dalasi D
DKK Danish Krone Kr
MKD Macedonian Denar Ден
DJF Djibouti Franc Fdj
DOP Dominican Peso RD$
VND Vietnamese Dong ₫
XCD East Caribbean Dollar $
EGP Egyptian Pound ج.م
SVC El Salvador Colon $
ETB Ethiopian Birr ብር
FKP Falkland Islands Pound £
FJD Fiji Dollar $
HUF Hungaria Forint Ft
GHS Ghana Cedi GH₵
GIP Gibraltar Pound £
HTG Haitian Gourde G
PYG ParaguayanGuarani ₲
GNF Guinea Franc FG
GYD Guyana Dollar G$
HKD Hong Kong Dollar HK$
UAH Ukranian Hryvnia ₴
ISK Iceland Krona Íkr
INR Indian Rupee ₹
IRR Iranian Rial ﷼
IQD Iraqi Dinar ع.د
JMD Jamaican Dollar $
JOD Jordanian Dinar د.ا
KES Kenyan Shilling Ksh
PGK Papua New Ginea Kina K
LAK Lao Kip ₭
HRK Croatian Kuna kn
KWD Kuwaiti Dinar د.ك
MWK MalawaianKwacha MK
AOA Angolan Kwanza Kz
MMK Burmese Kyat K
GEL Georgian Lari ლ
LBP Lebanese Pound ل.ل
ALL Albanian Lek L
HNL Honduran Lempira L
SLL Sierra Leonean Leone Le
LRD Liberian Dollar L$
LYD Libyan Dinar ل.د
SZL Swazi Lilangeni L
LSL Loti L
MGA Malagasy Ariary Ar
MYR Malaysian Ringgit RM
MUR Mauritius Rupee ₨
MXN Mexican Peso $
MDL Moldovan Leu L
MAD Moroccan Dirham MAD
MZN Mozambique Metical MT
NGN Nigerian Naira ₦
ERN Eritrean Nakfa نافكا
NAD Namibia Dollar N$
NPR Nepalese Rupee रू
ANG Netherlands Antillean Guilder ƒ
ILS New Israeli Sheqel ₪
TWD New Taiwan Dollar NT$
NZD New Zealand Dollar $
BTN Ngultrum Nu.
KPW North Korean Won ₩
NOK Norwegian Krone kr
PEN Nuevo Sol S/
TOP Tongan Pa’anga T$
PKR Pakistan Rupee ₨
MOP Pataca MOP$
CUC Peso Convertible CUC$
UYU Peso Uruguayo $U
PHP Philippine Peso ₱
GBP Pound Sterling £
BWP Botswanan Pula P
QAR Qatari Rial ر.ق
GTQ Guatemalan Quetzal Q
ZAR South African Rand R
OMR Rial Omani ر.ع.
KHR Cambodian Riel ៛
RON Romanian Leu lei
MVR Maldivian Rufiyaa Rf
IDR Indonesian Rupiah Rp
RUB Russian Ruble ₽
RWF Rwanda Franc R₣
SHP Saint Helena Pound £
SAR Saudi Riyal ﷼‎
RSD Serbian Dinar din
SCR Seychelles Rupee SRe
SGD Singapore Dollar $
SBD Solomon Islands Dollar Si$
KGS Som Лв
SOS Somali Shilling Sh
TJS Tajikistani Somoni ЅM
LKR Sri Lanka Rupee ரூ
SDG Sudanese Pound ج.س.
SRD Surinam Dollar $
SEK Swedish Krona kr
CHF Swiss Franc SFr
SYP Syrian Pound £S
BDT Bangeladash Taka ৳
WST Tala WS$
TZS Tanzanian Shilling TSh
KZT Kazahstani Tenge ₸
TTD Trinidad and Tobago Dollar TT$
MNT Tugrik ₮
TND Tunisian Dinar د.ت
TRY Turkish Lira ₺
TMT Turkmenistan New Manat T
AED UAE Dirham د.إ
UGX Uganda Shilling USh
UZS Uzbekistan Sum so'm
VUV Vanuatu Vatu VT
KRW Won ₩
YER Yemeni Rial ﷼
JPY Yen ¥
ZMW Zambian Kwacha ZK
ZWL Zimbabwe Dollar Z$
PLN Polish Zloty zł