NAV
shell python javascript

Introduction

Zota MG Deposit API enables Zota merchants to:

Before You Begin

In order to use this API, a merchant must first receive from Zota 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.

Deposit Flow

Payment Form Integration

  1. End-user requests a payment from merchant server.
  2. Merchant server sends a Deposit Request to Zota server.
  3. Zota server responds with an orderID, a unique order identifier, and with a depositUrl, url of the payment page.
  4. Merchant server redirects the waiting end-user to depositUrl.
  5. Merchant server starts sending an Order Status Request to Zota servers every 10-15 seconds, until end-user returns or a callback arrives.
  6. End-user submits his payment, and is being redirected back to merchant redirectUrl.
  7. Finally, Zota server sends merchant server callbackUrl a callback notification of the payment result (*).

Card Payment Integration

  1. End-user submits his card details to merchant server.
  2. Merchant server sends a Deposit Request to Zota server and receives in the response depositUrl which is the URL to which the request containing the card data should be posted.
  3. Merchant server sends request with card data to the provided deposit URL in the previous step.
  4. Zota server responds with an orderID, a unique order identifier, and with a status, the status of the requested order (e.g PROCESSING).
  5. In the meanwhile, merchant displays a 'waiting page' to the end-user.
  6. Merchant server starts sending an Order Status Request to Zota servers every 10-15 seconds, until order gets the final status or gets the status PENDING with url3dSecure.
  7. If callbackUrl is included in the Deposit Request, the final status or PENDING status with url3dSecure will be sent to the callbackUrl.
  8. If the order status is PENDING and pending3dSecure is TRUE, merchant server must redirect the end-user to the provided url3dSecure
  9. End-user fills extra info (e.g 3D Secure), and is being redirected back to merchant redirectUrl.
  10. Finally, Zota server sends merchant server callbackUrl a callback notification of the payment result (*).

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

Authentication

In order for Zota 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 tool for each of the signing use-cases.

Merchant Endpoints

The EndpointID represents the API destination that each deposit request must be submitted to for any particular payment solution. By design, each endpoint supports only one specific currency. Once your merchant application is approved by Zota, you will be provided with a full list of endpoints for your account, specific to the solution(s) requested.

Merchant Endpoint Groups

The EndpointGroupID is a means to consolidate all or part of a merchant’s endpoints into a single, multi-currency API destination. Requests made to an endpoint group will accept the orderCurrency value for any EndpointID that is included in said group and route the request accordingly.

Endpoint groups are not issued to merchants by default but are available upon request.

Deposit Request

Context

The whole deposit flow starts when the end-user attempts to make a payment and sends a request to merchants' server.

Merchant server then should send a signed Deposit Request to Zota server, while holding the user with some kind of a 'loading' sign.

Issue a Deposit Request

Initiates the payment process.

HTTP Request

POST /api/v1/deposit/request/EndpointID/ or
POST /api/v1/deposit/request/group/EndpointGroupID/

Content-Type: application/json

Merchant -> Zota

Request Parameters

Deposit Request example

curl -X POST \
    "https://api.zotapay.com/api/v1/deposit/request/1050/" \
    -H "Content-Type: application/json" \
    -d '{
        "merchantOrderID": "QvE8dZshpKhaOmHY",
        "merchantOrderDesc": "Test order",
        "orderAmount": "500.00",
        "orderCurrency": "THB",
        "customerEmail": "[email protected]",
        "customerFirstName": "John",
        "customerLastName": "Doe",
        "customerAddress": "5/5 Moo 5 Thong Nai Pan Noi Beach, Baan Tai, Koh Phangan",
        "customerCountryCode": "TH",
        "customerCity": "Surat Thani",
        "customerZipCode": "84280",
        "customerPhone": "+66-77999110",
        "customerIP": "103.106.8.104",
        "redirectUrl": "https://www.example-merchant.com/payment-return/",
        "callbackUrl": "https://www.example-merchant.com/payment-callback/",
        "customParam": "{\"UserId\": \"e139b447\"}",
        "checkoutUrl": "https://www.example-merchant.com/account/deposit/?uid=e139b447",
        "signature": "47d7ed292cf10e689b311ef5573eddbcc8505fe51e20d3f74e6b33756d96800b"
    }'
import requests  # pip install requests

url = 'https://api.zotapay.com/api/v1/deposit/request/1050/'
payload = {
    "merchantOrderID": "QvE8dZshpKhaOmHY",
    "merchantOrderDesc": "Test order",
    "orderAmount": "500.00",
    "orderCurrency": "THB",
    "customerEmail": "[email protected]",
    "customerFirstName": "John",
    "customerLastName": "Doe",
    "customerAddress": "5/5 Moo 5 Thong Nai Pan Noi Beach, Baan Tai, Koh Phangan",
    "customerCountryCode": "TH",
    "customerCity": "Surat Thani",
    "customerZipCode": "84280",
    "customerPhone": "+66-77999110",
    "customerIP": "103.106.8.104",
    "redirectUrl": "https://www.example-merchant.com/payment-return/",
    "callbackUrl": "https://www.example-merchant.com/payment-callback/",
    "customParam": "{\"UserId\": \"e139b447\"}",
    "checkoutUrl": "https://www.example-merchant.com/account/deposit/?uid=e139b447",
    "signature": "47d7ed292cf10e689b311ef5573eddbcc8505fe51e20d3f74e6b33756d96800b"
}
headers = {'content-type': 'application/json'}

try:
  response = requests.post(url, json=payload, headers=headers)
except Exception as e:
  raise Exception(f"deposit 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/deposit/request/1050/',
  method: 'POST',
  json: {
    "merchantOrderID": "QvE8dZshpKhaOmHY",
    "merchantOrderDesc": "Test order",
    "orderAmount": "500.00",
    "orderCurrency": "THB",
    "customerEmail": "[email protected]",
    "customerFirstName": "John",
    "customerLastName": "Doe",
    "customerAddress": "5/5 Moo 5 Thong Nai Pan Noi Beach, Baan Tai, Koh Phangan",
    "customerCountryCode": "TH",
    "customerCity": "Surat Thani",
    "customerZipCode": "84280",
    "customerPhone": "+66-77999110",
    "customerIP": "103.106.8.104",
    "redirectUrl": "https://www.example-merchant.com/payment-return/",
    "callbackUrl": "https://www.example-merchant.com/payment-callback/",
    "customParam": "{\"UserId\": \"e139b447\"}",
    "checkoutUrl": "https://www.example-merchant.com/account/deposit/?uid=e139b447",
    "signature": "47d7ed292cf10e689b311ef5573eddbcc8505fe51e20d3f74e6b33756d96800b"
  }
};

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 Yes
customerFirstName 128 End user first name Yes
customerLastName 128 End user last name Yes
customerAddress 128 End user address Yes
customerCountryCode 2 End user country, two-letter ISO 3166-1 Alpha-2 country code. see Country Codes for a full list of country codes. Yes
customerCity 128 End user city Yes
customerState 3 Required for US, CA and AU countries. End user state/province, two-letter state code. See State Codes for a full list of state codes. Conditional
customerZipCode 15 End user postal code Yes
customerPhone 15 End user full international telephone number, including country code Yes
customerIP 64 End user IPv4/IPv6 address Yes
customerPersonalID 20 End user personal ID number No
customerBankCode 16 End user bank code No
customerBankAccountNumber 64 End user bank account number No
redirectUrl 255 URL for end user redirection upon transaction completion, regardless of order status, see Final Redirection section below for more details Yes
callbackUrl 255 URL the order status will be sent to, see Callback section below for more details No
checkoutUrl 256 The original URL from where the end-user started the deposit request (a URL in Merchants' website) Yes
customParam 128 Merchant-defined optional custom parameter No
language 2 Preferred payment form language No
signature 64 Request checksum encrypted with SHA-256, see Signature section below for more details Yes

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

{
    "code": "200",
    "data": {
        "depositUrl": "https://api.zotapay.com/api/v1/deposit/init/8b3a6b89697e8ac8f45d964bcc90c7ba41764acd/",
        "merchantOrderID": "QvE8dZshpKhaOmHY",
        "orderID": "8b3a6b89697e8ac8f45d964bcc90c7ba41764acd"
    }
}

A non-successful response from Zota 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

Zota -> Merchant

Name Description
code A status code representing the acceptance of the request by Zota 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: depositUrl, merchantOrderID and orderID. Please see the table below for detailed information regarding these fields.

The data Response Parameter

Field Description
depositUrl The URL of the payment form, merchant should redirect the (waiting) end-user to this URL (HTTP 302).
merchantOrderID Merchants' order unique identifier, provided in the original Deposit Request.
orderID Order unique identifier generated by Zota, should be then used for Order Status Requests.

Signature

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

EndpointID + merchantOrderID + orderAmount + customerEmail + MerchantSecretKey

Signing a Deposit Request


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

# concatenate values into a single string
str="${endpointID}${merchantOrderID}${orderAmount}${customerEmail}${secretKey}"
echo $str
# 1050QvE8dZshpKhaOmHY500.00customer@email-address.comEXAMPLE-SECRET-KEY

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

from hashlib import sha256

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

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

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

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

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

console.log(sig); // 47d7ed292cf10e689b311ef5573eddbcc8505fe51e20d3f74e6b33756d96800b

Card Payment Integration

In case of merchant collects card information on their side and wish to include it in the request, the deposit request (following the documentation) should be posted including the direct path parameter:

POST /api/v1/deposit/request/direct/EndpointID/ or
POST /api/v1/deposit/request/direct/group/EndpointGroupID/

HTTP Response (Card Integration)

A successful response from Zota server to the deposit request on direct endpoints:

{
    "code": "200",
    "data": {
        "merchantOrderID": "1721809513",
        "orderID": "32530298",
        "depositUrl": "https://cde-secure.zota.com/api/v1/deposit/process/direct/1/32530298"
    }
}

Content-Type: application/json

Zota -> Merchant

Name Description
code A status code representing the acceptance of the request by Zota 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: depositUrl, merchantOrderID and orderID. Please see the table below for detailed information regarding these fields.

The data Response Parameter

Field Description
depositUrl The URL to which the request containing the card data should be posted.
merchantOrderID Merchants' order unique identifier, provided in the original Deposit Request.
orderID Order unique identifier generated by Zota, should be then used for Order Status Requests.

HTTP Request (Card Data)

Content-Type: application/json

Merchant -> Zotapay

Name Max. Length Description Required
data n/a Contains the card data object, see details below Yes
signature 64 Request checksum encrypted with SHA-256, see Signature section below for more details Yes

Signing a Card Data Request

#!/bin/bash

echo "$@"

# prepare vars
cardNum=4111111111111111
holderName="John Doe"
expYear=2025
expMonth=12
cvv=123
secretKey=EXAMPLE-SECRET-KEY

# concatenate values into a single string
str="${cardNum}${holderName}${expYear}${expMonth}${cvv}${secretKey}"
echo $str
# 4111111111111111John Doe202512123EXAMPLE-SECRET-KEY

# create a sha256 hash of the string
sig=$(echo -n ${str} | openssl dgst -sha256 -hex)
echo $sig
# c118fd59adf8a8c335df4122a2a15cadd60023c290faf1b078252feeaf9b479a
from hashlib import sha256

# prepare vars
card_num = "4111111111111111"
holder_name = "John Doe"
exp_year = "2025"
exp_month = "12"
cvv = "123"
secret_key = "EXAMPLE-SECRET-KEY"

# concatenate values into a single string
s = f"{card_num}{holder_name}{exp_year}{exp_month}{cvv}{secret_key}"
print(s)

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

const cardNum = "4111111111111111";
const holderName = "John Doe";
const expYear = "2025";
const expMonth = "12";
const cvv = "123";
const secretKey = "EXAMPLE-SECRET-KEY";

const s = cardNum + holderName + expYear + expMonth + cvv + secretKey;
const sig = crypto.createHash('sha256').update(s).digest('hex');

console.log(sig); // c118fd59adf8a8c335df4122a2a15cadd60023c290faf1b078252feeaf9b479a

The signature is formed from all card parameters along with the API KEY and SHA256 hashed:
cardNum + holderName + expYear + expMonth + cvv + MerchantSecretKey

The data object structure:

Deposit Card Data Request example

curl -X POST \
    "https://cde-secure.zota.com/api/v1/deposit/process/direct/1/32530298" \
    -H "Content-Type: application/json" \
    -d '{
        "data": {
          "cardNum": "4917610000000000",
          "cvv": "0001",
          "expMonth": 10,
          "expYear": 2031,
          "holderName": "John Doe"
        },
        "signature": "3559f675ac345102f7fbf80dcd229637467899203665bf6cf7dfed9a4b34a504"
      }'
import requests  # pip install requests

url = 'https://cde-secure.zota.com/api/v1/deposit/process/direct/1/32530298'
payload = {
  "data": {
    "cardNum": "4917610000000000",
    "cvv": "0001",
    "expMonth": 10,
    "expYear": 2031,
    "holderName": "John Doe"
  },
  "signature": "3559f675ac345102f7fbf80dcd229637467899203665bf6cf7dfed9a4b34a504"
}
headers = {'content-type': 'application/json'}

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

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

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

const opts = {
  uri: 'https://cde-secure.zota.com/api/v1/deposit/process/direct/1/32530298',
  method: 'POST',
  json: {
    "data": {
      "cardNum": "4917610000000000",
      "cvv": "0001",
      "expMonth": 10,
      "expYear": 2031,
      "holderName": "John Doe"
    },
    "signature": "3559f675ac345102f7fbf80dcd229637467899203665bf6cf7dfed9a4b34a504"
  }
};

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
cardNum 16 Card number Yes
holderName 64 Card holder name as appears on card Yes
expMonth 2 Expiration month (e.g "02") Yes
expYear 4 Expiration Year (e.g "2020" or just "20") Yes
cvv 4 CVV / Security code Yes

HTTP Response

Content-Type: application/json

Zotapay -> Merchant

Name Description
code A status code representing the acceptance of the request by Zota server.
data If code is 200 the data will include status and orderID.

The data object structure:

Name Description
status Transaction status, see Order Statuses for a full list of statuses.
orderID Order unique identifier generated by Zota, should be then used for Order Status Requests.

A successful response from Zota server to the deposit direct request:

{
    "code": "200",
    "data": {
        "status": "PENDING",
        "orderID": "32530310"
    }
}

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 Deposit Request is sent to Zota server and orderID is returned, merchant server should start polling for transaction status (10-15 seconds interval).

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

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

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

  3. In case of Card Payment Integration, when the status is PENDING (see more in Card 3D Secure).

Issue an Order Status Request

HTTP Request

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

Merchant -> Zota

Query Parameters

Order Status Request example

# prepare vars
mid=EXAMPLE-MERCHANT-ID
moid=QvE8dZshpKhaOmHY
oid=8b3a6b89697e8ac8f45d964bcc90c7ba41764acd
ts=1564617600
sig=4a01f6cc95e6a7a771afe0e49f59fb572dbadec449f175d978e722b97ee9785d

# 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 = "QvE8dZshpKhaOmHY"
oid = "8b3a6b89697e8ac8f45d964bcc90c7ba41764acd"
ts = "1564617600"  # str(int(time.time()))
sig = "4a01f6cc95e6a7a771afe0e49f59fb572dbadec449f175d978e722b97ee9785d"

# 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 = "QvE8dZshpKhaOmHY";
const oid = "8b3a6b89697e8ac8f45d964bcc90c7ba41764acd";
const ts = "1564617600";  // parseInt((new Date().getTime()) / 1000).toString()
const sig = "4a01f6cc95e6a7a771afe0e49f59fb572dbadec449f175d978e722b97ee9785d";

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 Zota (see Before You Begin section) Yes
orderID 128 Order unique identifier generated by Zota 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

Zota -> Merchant

Name Description
code A status code representing the acceptance of the request by Zota 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: depositUrl, merchantOrderID and orderID. Please see the table below for detailed information regarding these fields.

The data Response Parameter

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

{
    "code": "200",
    "data": {
        "type": "SALE",
        "status": "PROCESSING",
        "errorMessage": "",
        "endpointID": "1050",
        "processorTransactionID": "",
        "orderID": "8b3a6b89697e8ac8f45d964bcc90c7ba41764acd",
        "merchantOrderID": "QvE8dZshpKhaOmHY",
        "amount": "500.00",
        "currency": "THB",
        "customerEmail": "[email protected]",
        "customParam": "{\"UserId\": \"e139b447\"}",
        "extraData": {
             "amountChanged": true,
             "amountRounded": true,
             "amountManipulated": false,
             "dcc": false,
             "originalAmount": "499.98",
             "paymentMethod": "INSTANT-BANK-WIRE",
             "selectedBankCode": "SCB",
             "selectedBankName": ""
         },
        "request": {
            "merchantID": "EXAMPLE-MERCHANT-ID",
            "orderID": "8b3a6b89697e8ac8f45d964bcc90c7ba41764acd",
            "merchantOrderID": "QvE8dZshpKhaOmHY",
            "timestamp": "1564617600"
        }
    }
}

A non-successful response from Zota 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: SALE.
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 Zota.
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 Zota environment, such as amountChanged (boolean), originalAmount (int), paymentMethod (string), etc.
request A Json object with a copy of the original Order Status Request sent by merchant server to Zota.

Signature

Every request must be signed by the merchant in order to be successfully authenticated by Zota 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=QvE8dZshpKhaOmHY
orderID=8b3a6b89697e8ac8f45d964bcc90c7ba41764acd
timestamp=1564617600
secretKey=EXAMPLE-SECRET-KEY

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

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

from hashlib import sha256

# prepare vars
mid = "EXAMPLE-MERCHANT-ID"
moid = "QvE8dZshpKhaOmHY"
oid = "8b3a6b89697e8ac8f45d964bcc90c7ba41764acd"
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 )  # 4a01f6cc95e6a7a771afe0e49f59fb572dbadec449f175d978e722b97ee9785d
const crypto = require('crypto'); // npm install crypto

const mid = "EXAMPLE-MERCHANT-ID";
const moid = "QvE8dZshpKhaOmHY";
const oid = "8b3a6b89697e8ac8f45d964bcc90c7ba41764acd";
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); // 4a01f6cc95e6a7a771afe0e49f59fb572dbadec449f175d978e722b97ee9785d

Card 3D Secure

Context

When integrating using the Card Payment Integration, after the Deposit Request was sent, order might enter a PENDING status, with 3D Secure input requirement from the end-user. Merchant will be notified about such event by callback (when callbackUrl is provided) and/or by performing an Order Status Request.

Example of a PENDING callback with 3D Secure requirements

{
    "type": "SALE",
    "status": "PENDING",
    "endpointID": "70210",
    "processorTransactionID": "04a1cade-1187-44e8-b555-843dc5a7211e",
    "orderID": "1502000",
    "merchantOrderID": "574c19d02b7f",
    "amount": "100.00",
    "currency": "USD",
    "customerEmail": "[email protected]",
    "customParam": "",
    "extraData": {
        "card": {
            "cvv": "***",
            "expiration": "03/2022",
            "holder": "card tester",
            "number": "111100***0000"
        },
        "cardData": {
            "bank": {},
            "brand": "",
            "country": {}
        },
        "pending3dSecure": true,            // <--------------
        "url3dSecure": "< URL >",           // <--------------
    },
    "originalRequest": {
        ...
    },
    "signature": "bd2097de35188dee5714b497f7b9aef78712c3207d33fbb94f863f2d9b404fa5"
}

## Handling 3D Secure Events

Merchant should react to such PENDING event by prompting the (already waiting) end-user with a 3D Secure form, which is provided by Zota as an HTML snippet in the callback / status-check response.

Please review the attached example of a PENDING callback with 3D Secure requirements. Especially note these 2 parameters inside of extraData:

When callback (or status-check response) status is PENDING, and extraData.pending3dSecure is true, merchant should redirect the end-user the url that was received in extraData.url3dSecure (popup / iframe is also a valid option).

After the user submits the form, the order processing will continue automatically, and merchant should still expect a final status for the order, either by callback, or by continuing the Order Status Request loop.

Order Completion

Context

After end-user submits the payment form, Zota:

End User Final Redirect

HTTP GET

Zota -> DepositRequest.redirectUrl

Query Parameters

Example Redirect URL

https://www.example-merchant.com/payment-return/?
          merchantOrderID=QvE8dZshpKhaOmHY
          &orderID=8b3a6b89697e8ac8f45d964bcc90c7ba41764acd
          &signature=da2d2d269792c78145edc12096732d2aba411c9eefd3c717d87993c7e4a4c523
          &status=APPROVED
Field Description
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.
orderID Order unique identifier generated by Zota.
merchantOrderID Merchant-defined unique order identifier.
signature Request checksum encrypted with SHA-256, see Signature section below for more details

Signature

When Zota redirects the end-user back to merchant's redirectUrl, this redirect request includes a signature query 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:

status + orderID + merchantOrderID + 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 Redirect Signature


# prepare vars
status=APPROVED
orderID=8b3a6b89697e8ac8f45d964bcc90c7ba41764acd
merchantOrderID=QvE8dZshpKhaOmHY
secretKey=EXAMPLE-SECRET-KEY

# concatenate values into a single string
str="${status}${orderID}${merchantOrderID}${secretKey}"
echo $str
# APPROVED8b3a6b89697e8ac8f45d964bcc90c7ba41764acdQvE8dZshpKhaOmHYEXAMPLE-SECRET-KEY

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

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

from hashlib import sha256

# prepare vars
status = "APPROVED"
oid = "8b3a6b89697e8ac8f45d964bcc90c7ba41764acd"
moid = "QvE8dZshpKhaOmHY"
secret = "EXAMPLE-SECRET-KEY"

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

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

const status = "APPROVED";
const oid = "8b3a6b89697e8ac8f45d964bcc90c7ba41764acd";
const moid = "QvE8dZshpKhaOmHY";
const secret = "EXAMPLE-SECRET-KEY";

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

console.log(sig); // da2d2d269792c78145edc12096732d2aba411c9eefd3c717d87993c7e4a4c523

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), Zota server will initiate an HTTP POST request to merchant callbackUrl provided in the original Deposit 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

Zota -> DepositRequest.callbackUrl

Request Parameters

Example Callback Notification

{
  "type": "SALE",
  "amount": "500.00",
  "status": "APPROVED",
  "orderID": "8b3a6b89697e8ac8f45d964bcc90c7ba41764acd",
  "currency": "THB",
  "extraData": {
    "amountChanged": true,
    "amountRounded": true,
    "amountManipulated": false,
    "dcc": false,
    "originalAmount": "499.98",
    "paymentMethod": "INSTANT-BANK-WIRE",
    "selectedBankCode": "SCB",
    "selectedBankName": ""
  },
  "signature": "062c0480aafd1faf735b987f5a2f878634d7931ffb3df256cdbfa77c31a2a4cc",
  "endpointID": "1050",
  "customParam": "{\"UserId\": \"e139b447\"}",
  "errorMessage": "",
  "customerEmail": "[email protected]",
  "merchantOrderID": "QvE8dZshpKhaOmHY",
  "originalRequest": {
    "merchantOrderID": "QvE8dZshpKhaOmHY",
    "merchantOrderDesc": "Test order",
    "orderAmount": "500.00",
    "orderCurrency": "THB",
    "customerEmail": "[email protected]",
    "customerFirstName": "John",
    "customerLastName": "Doe",
    "customerAddress": "5/5 Moo 5 Thong Nai Pan Noi Beach, Baan Tai, Koh Phangan",
    "customerCountryCode": "TH",
    "customerCity": "Surat Thani",
    "customerZipCode": "84280",
    "customerPhone": "+66-77999110",
    "customerIP": "103.106.8.104",
    "redirectUrl": "https://www.example-merchant.com/payment-return/",
    "callbackUrl": "https://www.example-merchant.com/payment-callback/",
    "customParam": "{\"UserId\": \"e139b447\"}",
    "checkoutUrl": "https://www.example-merchant.com/account/deposit/?uid=e139b447",
    "signature": "47d7ed292cf10e689b311ef5573eddbcc8505fe51e20d3f74e6b33756d96800b",
    "customerState": "",
  },
  "processorTransactionID": "000139821"
}
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 Zota.
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 Zota's environemnt, such as amountChanged (boolean), originalAmount (int), paymentMethod (string), etc.
originalRequest A Json object with a copy of the original Deposit Request sent by merchant server to Zota.
signature Request checksum encrypted with SHA-256, see Request Signature section below for more details

Signature

When Zota 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=8b3a6b89697e8ac8f45d964bcc90c7ba41764acd
merchantOrderID=QvE8dZshpKhaOmHY
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
# 10508b3a6b89697e8ac8f45d964bcc90c7ba41764acdQvE8dZshpKhaOmHYAPPROVED500.00customer@email-address.comEXAMPLE-SECRET-KEY

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

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

from hashlib import sha256

# prepare vars
endpoint = "1050"
oid = "8b3a6b89697e8ac8f45d964bcc90c7ba41764acd"
moid = "QvE8dZshpKhaOmHY"
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 )  # 062c0480aafd1faf735b987f5a2f878634d7931ffb3df256cdbfa77c31a2a4cc
const crypto = require('crypto'); // npm install crypto

const endpoint = "1050";
const oid = "8b3a6b89697e8ac8f45d964bcc90c7ba41764acd";
const moid = "QvE8dZshpKhaOmHY";
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); // 062c0480aafd1faf735b987f5a2f878634d7931ffb3df256cdbfa77c31a2a4cc

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 -> Zota

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 Zota (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 and PAYOUT No
signature 64 Request checksum encrypted with SHA-256, see Signature section below for more details. Yes

HTTP Response

Content-Type: text/csv

Zota -> 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 Zota 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

Exchange Rates

Context

This API endpoint provides merchants with access to the effective rates for currency conversions on a specific date and for a particular order. It is essential for merchants who want to calculate the cost of their transactions accurately.

Issue an Exchange Rates Request

HTTP Request

GET /api/v1/query/exchange-rates/

Query Parameters

Exchange Rates Request example

# prepare vars
mid='EXAMPLE-MERCHANT-ID'
request_id='d6da50a9-aca4-4d6f-a022-f487a127b54d'
ts='1695200538'
order_type='SALE'
order_id='32452684'
date=''
sig='63adcf671d9f23ab5184a05234d1ddb8a6be0b1f2570be739bb96ccedcf725e7'

# prepare query string
qs="merchantID=${mid}&requestID=${request_id}&date=${date}&timestamp=${ts}&orderType=${order_type}&orderID=${order_id}&signature=${sig}"

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

# prepare vars
mid='EXAMPLE-MERCHANT-ID'
request_id='d6da50a9-aca4-4d6f-a022-f487a127b54d'
ts='1695200538' # str(int(time.time()))
order_type='SALE'
order_id='32452684'
date=''
sig='63adcf671d9f23ab5184a05234d1ddb8a6be0b1f2570be739bb96ccedcf725e7'

# prepare query string
qs=f"merchantID={mid}&requestID={request_id}&date={date}&timestamp={ts}&orderType={order_type}&orderID={order_id}&signature={sig}"
url = f"https://api.zotapay.com/api/v1/query/exchange-rates/?{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 request_id='d6da50a9-aca4-4d6f-a022-f487a127b54d'
const ts='1695200538' // parseInt((new Date().getTime()) / 1000).toString()
const order_type='SALE'
const order_id='32452684'
const date=''
const sig='63adcf671d9f23ab5184a05234d1ddb8a6be0b1f2570be739bb96ccedcf725e7'

const qs = `merchantID=${mid}&requestID=${request_id}&date=${date}&timestamp=${ts}&orderType=${order_type}&orderID=${order_id}&signature=${sig}`;
const url = `https://api.zotapay.com/api/v1/query/exchange-rates/?${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 Zota (see Before You Begin section) Yes
orderID 128 Order unique identifier generated by Zota No
date 10 Get rates for specific date, format YYYY-MM-DD, e.g 2019-11-01. If orderID is not defined, then date is required. No
requestID 36 A unique identifier for the request, must be of type uuid4 Yes
timestamp 15 Unix timestamp of the request time Yes
orderType 128 Order Type, either SALE, PAYOUT or REVERSAL. Yes
signature 64 Request checksum encrypted with SHA-256, see Signature section below for more details. Yes

HTTP Response

Content-Type: application/json

Response payload will be returned as a JSON object.

- orderID is Specified

If an orderID is specified, the API will return the effective exchange rate used for the given order and other relevant accounting parameters.

A successful response with orderID specified in the request.

{
    "code": "200",
    "data": {
        "exchangeRates": {
            "balanceCurrency": "USD",
            "balanceAccount": "EXAMPLE-MERCHANT-USD",
            "isConverted": true,
            "conversionRate": "0.01300121",
            "effectiveAmount": "0.1300121",
            "toMerchantBalance": "-0.22323821",
            "totalFees": "0.3532503",
            "rollingReserve": "0"
        }
    }
}

- orderID is Not Specified

The API will return the effective rate for all currency pairs, from "any supported currency" to the "merchant base currency".

A successful response with orderID NOT specified in the request.

{
    "code": "200",
    "data": {
        "exchangeRates": {
            "AED": {
                "CNY": "1.8645665591266114"
            },
            "AFN": {
                "CNY": "0.0799337999497419"
            },
            "AMD": {
                "CNY": "0.0175356317659951"
            }
        }
    }
}

Signature

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

MerchantID + MerchantSecretKey + requestID + date + timestamp + OrderID

Signing an Orders Report Request


# prepare vars
mid='EXAMPLE-MERCHANT-ID'
secret='EXAMPLE-SECRET-KEY'
request_id='d6da50a9-aca4-4d6f-a022-f487a127b54d'
date=''
ts='1695200538'
order_type='SALE'
order_id='32452684'
# concatenate values into a single string
str="${mid}${secret}${request_id}${date}${ts}${order_id}"
echo $str
# EXAMPLE-MERCHANT-IDEXAMPLE-SECRET-KEYd6da50a9-aca4-4d6f-a022-f487a127b54d169520053832452684

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

from hashlib import sha256

# prepare vars
mid='EXAMPLE-MERCHANT-ID'
secret='EXAMPLE-SECRET-KEY'
request_id='d6da50a9-aca4-4d6f-a022-f487a127b54d'
date=''
ts='1695200538' # str(int(time.time()))
order_type='SALE'
order_id='32452684'

# concatenate values into a single string
s = f"{mid}{secret}{request_id}{date}{ts}{order_id}"

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

mid='EXAMPLE-MERCHANT-ID'
secret='EXAMPLE-SECRET-KEY'
request_id='d6da50a9-aca4-4d6f-a022-f487a127b54d'
date=''
ts='1695200538' // parseInt((new Date().getTime()) / 1000).toString()
order_type='SALE'
order_id='32452684'
const s = mid + secret + request_id + date + ts + order_id;
const sig = crypto.createHash('sha256').update(s).digest('hex');

console.log(sig); // de2c787eb8ed6ba83812c0bf5ec9aa3c24ca20b3a4e906c85e1b036eaf558686

Error Codes

Context

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

HTTP Response

Content-Type: application/json

Zota -> Merchant

Name Description
code A status code representing the acceptance of the request by Zota 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.
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.

Test Cards

Use the following test cards in our Sandbox environment in order to simulate different statuses and cases for Card Payment Integration.

Card Number Card Type Status 3D Secure
4222222222222222 Visa Approved No
4222222222347466 Visa Pending Yes
5555555555555557 MasterCard Approved No
5595883393160089 MasterCard Pending Yes
3555555555555552 JCB Approved No
3530185156387088 JCB Pending Yes
0000000000000000 - Error No
0000000000001111 - Filtered No

3D Secure Sandbox Form

Value Status
12345 Approved

Any other card number / 3D Secure value will result with DECLINED status.

Test Cards V2

In order to test your integration with our payment gateway, you can use our sandbox environment and test credit cards. The sandbox environment simulates the behavior of our production environment, but without processing actual payments. This allows you to test your integration thoroughly before going live.

Please note that you should never use real credit card information in the sandbox environment or any testing environment. Instead, you should use the following test credit card information:

Card Number Card Type
4222222222222222
Visa
5555555555555557
MasterCard
3530185156387088
JCB
6011000000000000
Discover
6759111111111111
Maestro
3411111111111111
Amex

Non-3D Orders:

The following CVV2 codes can be used in the Sandbox environment to get different statuses for test orders which are not 3D secured.

Value Status
000 APPROVED
001 DECLINED
010 UNKNOWN
1234 / any other 4 digits CVV2 code PENDING + 3D Secure

Please note that any other 3-digit CVV2 values will result in an ERROR status.

3D Orders

In order to test the 3D Secure flow, use any 4 digit CVV2 code.

This will invoke the 3D Secure authentication process, and you will need to use one of the below OTP codes to complete the transaction with the desired status.

For 3D-secured orders, you can use the following OTP codes to simulate different test cases:

Value Status
123456 APPROVED
654321 DECLINED
000000 UNKNOWN

Please note that any other 3D Secure OTP value will result in an ERROR 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ł

Country Codes

Country Code Country Name
AF Afghanistan
AL Albania
DZ Algeria
AS American Samoa
AD Andorra
AO Angola
AI Anguilla
AQ Antarctica
AG Antigua and Barbuda
AR Argentina
AM Armenia
AW Aruba
AU Australia
AT Austria
AZ Azerbaijan
BS Bahamas
BH Bahrain
BD Bangladesh
BB Barbados
BY Belarus
BE Belgium
BZ Belize
BJ Benin
BM Bermuda
BT Bhutan
BO Bolivia
BQ Bonaire, Sint Eustatius and Saba
BA Bosnia and Herzegovina
BW Botswana
BV Bouvet Island
BR Brazil
IO British Indian Ocean Territory
BN Brunei Darussalam
BG Bulgaria
BF Burkina Faso
BI Burundi
CV Cabo Verde
KH Cambodia
CM Cameroon
CA Canada
KY Cayman Islands
CF Central African Republic
TD Chad
CL Chile
CN China
CX Christmas Island
CC Cocos (Keeling) Islands
CO Colombia
KM Comoros
CD Congo Democratic Republic
CG Congo
CK Cook Islands
CR Costa Rica
HR Croatia
CU Cuba
CW Curaçao
CY Cyprus
CZ Czechia
CI Cote d Ivoire
DK Denmark
DJ Djibouti
DM Dominica
DO Dominican Republic
EC Ecuador
EG Egypt
SV El Salvador
GQ Equatorial Guinea
ER Eritrea
EE Estonia
SZ Swaziland
ET Ethiopia
FK Falkland Islands (Malvinas)
FO Faroe Islands
FJ Fiji
FI Finland
FR France
GF French Guiana
PF French Polynesia
TF French Southern Territories
GA Gabon
GM Gambia
GE Georgia
DE Germany
GH Ghana
GI Gibraltar
GR Greece
GL Greenland
GD Grenada
GP Guadeloupe
GU Guam
GT Guatemala
GG Guernsey
GN Guinea
GW Guinea-Bissau
GY Guyana
HT Haiti
HM Heard & McDonald Islands
VA Holy See
HN Honduras
HK Hong Kong
HU Hungary
IS Iceland
IN India
ID Indonesia
IR Iran
IQ Iraq
IE Ireland
IM Isle of Man
IL Israel
IT Italy
JM Jamaica
JP Japan
JE Jersey
JO Jordan
KZ Kazakhstan
KE Kenya
KI Kiribati
KP Korea (Democratic Republic)
KR Korea (Republic)
KW Kuwait
KG Kyrgyzstan
LA Lao Democratic Republic
LV Latvia
LB Lebanon
LS Lesotho
LR Liberia
LY Libya
LI Liechtenstein
LT Lithuania
LU Luxembourg
MO Macao
MK Macedonia
MG Madagascar
MW Malawi
MY Malaysia
MV Maldives
ML Mali
MT Malta
MH Marshall Islands
MQ Martinique
MR Mauritania
MU Mauritius
YT Mayotte
MX Mexico
FM Micronesia
MD Moldova
MC Monaco
MN Mongolia
ME Montenegro
MS Montserrat
MA Morocco
MZ Mozambique
MM Myanmar
NA Namibia
NR Nauru
NP Nepal
NL Netherlands
NC New Caledonia
NZ New Zealand
NI Nicaragua
NE Niger
NG Nigeria
NU Niue
NF Norfolk Island
MP Northern Mariana Islands
NO Norway
OM Oman
PK Pakistan
PW Palau
PS Palestine, State of
PA Panama
PG Papua New Guinea
PY Paraguay
PE Peru
PH Philippines
PN Pitcairn
PL Poland
PT Portugal
PR Puerto Rico
QA Qatar
RO Romania
RU Russian Federation
RW Rwanda
RE Réunion
BL Saint Barthélemy
SH Saint Helena
KN Saint Kitts and Nevis
LC Saint Lucia
MF Saint Martin (French part)
PM Saint Pierre and Miquelon
VC Saint Vincent and the Grenadines
WS Samoa
SM San Marino
ST Sao Tome and Principe
SA Saudi Arabia
SN Senegal
RS Serbia
SC Seychelles
SL Sierra Leone
SG Singapore
SX Sint Maarten (Dutch part)
SK Slovakia
SI Slovenia
SB Solomon Islands
SO Somalia
ZA South Africa
GS South Georgia
SS South Sudan
ES Spain
LK Sri Lanka
SD Sudan
SR Suriname
SJ Svalbard and Jan Mayen
SE Sweden
CH Switzerland
SY Syrian Arab Republic
TW Taiwan
TJ Tajikistan
TZ Tanzania, United Republic of
TH Thailand
TL Timor-Leste
TG Togo
TK Tokelau
TO Tonga
TT Trinidad and Tobago
TN Tunisia
TR Turkey
TM Turkmenistan
TC Turks and Caicos Islands
TV Tuvalu
UG Uganda
UA Ukraine
AE United Arab Emirates
GB United Kingdom
US United States of America
UY Uruguay
UZ Uzbekistan
VU Vanuatu
VE Venezuela
VN Vietnam
VG Virgin Islands (British)
VI Virgin Islands (U.S.)
WF Wallis and Futuna
EH Western Sahara
YE Yemen
ZM Zambia
ZW Zimbabwe
AX Aland Islands
QZ Kosovo
AN Netherlands Antilles
UM United States Minor Outlying Islands

State Codes

Country Code State Code State Name
AU AC Australian Capital Territory
AU NS New South Wales
AU NT Northern Territory
AU QL Queensland
AU SA South Australia
AU TA Tasmania
AU VI Victoria
AU WA Western Australia
CA AB Alberta
CA BC British Columbia
CA MB Manitoba
CA NB New Brunswick
CA NL Newfoundland and Labrador
CA NT Northwest Territories
CA NS Nova Scotia
CA NU Nunavut
CA ON Ontario
CA PE Prince Edward Island
CA QC Quebec
CA SK Saskatchewan
CA YT Yukon
US AL Alabama
US AK Alaska
US AS American Samoa
US AZ Arizona
US AR Arkansas
US CA California
US CO Colorado
US CT Connecticut
US DE Delaware
US DC District of Columbia
US FL Florida
US GA Georgia
US GU Guam
US HI Hawaii
US ID Idaho
US IL Illinois
US IN Indiana
US IA Iowa
US KS Kansas
US KY Kentucky
US LA Louisiana
US ME Maine
US MD Maryland
US MA Massachusetts
US MI Michigan
US MN Minnesota
US MS Mississippi
US MO Missouri
US MT Montana
US NE Nebraska
US NV Nevada
US NH New Hampshire
US NJ New Jersey
US NM New Mexico
US NY New York
US NC North Carolina
US ND North Dakota
US OH Ohio
US OK Oklahoma
US OR Oregon
US PA Pennsylvania
US PR Puerto Rico
US RI Rhode Island
US SC South Carolina
US SD South Dakota
US TN Tennessee
US TX Texas
US UT Utah
US VT Vermont
US VI Virgin Islands
US VA Virginia
US WA Washington
US WV West Virginia
US WI Wisconsin
US WY Wyoming

Supported Language Codes

Language Code
Japanese ja
Chinese zh
Korean ko
Malay ms
Thai th
Vietnamese vi
Indonesian id
Spanish es
Portuguese pt
French fr
Italian it
Russian ru

Callback IPs

To ensure seamless integration and secure communication between Metagate and your systems, it's crucial to recognize and allowlist the specific IP addresses we use for sending callbacks. This section provides an overview of our production and sandbox environment's IP addresses. Configuring your systems to accept callbacks from these addresses is essential for receiving transaction updates.

Production server IPs:

18.158.191.139, 18.198.240.187, 3.122.154.23, 13.36.22.5, 15.236.215.248, 35.180.81.96

Sandbox server IPs:

18.198.219.119, 3.124.25.16, 3.125.82.248