ZebraPay

API Reference

Switch between Payin and Payout. Base URLs are issued at onboarding.

Overview

Hosted UPI payin: create an order, redirect the customer, then confirm via Status Enquiry / Callback. Replace {BASE_URL} with the URL from onboarding. Amount in INR (CURRENCY_CODE=356), e.g. 100 or 12.50.

  • /api/v1/payin/paymentrequest — create + redirect
  • /api/v1/payin/statusenquiry — poll status
  • {Callback_URL} — async status notify

Credentials

FieldTypeReqDescription
PAY_IDStringYesIssued at onboarding
Secret_KeyStringYesRequest signing salt
Base_URLStringYesTest / production base (private)
Callback_URLStringYesYour status webhook
Return_URLStringYesCustomer return page

HASH signing

Sign every request: sort fields (excl. HASH) → KEY=VALUE joined by ~ → append Secret Key → SHA-256 → UPPERCASE.

Example fields

{
  "PAY_ID": "1766566497559252",
  "ORDER_ID": "TTO2025043342312951",
  "AMOUNT": "100",
  "TXNTYPE": "SALE",
  "RETURN_URL": "https://yoursite.com/return",
  "CUST_NAME": "test",
  "USER_ID": "20591696",
  "CUST_STREET_ADDRESS1": "Test",
  "CUST_ZIP": "TWQ123",
  "CUST_PHONE": "7417006565",
  "CUST_EMAIL": "test@gmail.com",
  "ORDER_DESC": "Payin",
  "CURRENCY_CODE": "356"
}

Base string + secret

AMOUNT=100~CURRENCY_CODE=356~CUST_EMAIL=test@gmail.com~CUST_NAME=test~CUST_PHONE=7417006565~CUST_STREET_ADDRESS1=Test~CUST_ZIP=TWQ123~ORDER_DESC=Payin~ORDER_ID=TTO2025043342312951~PAY_ID=1766566497559252~RETURN_URL=https://yoursite.com/return~TXNTYPE=SALE~USER_ID=20591696{Secret_Key}

HASH

018BC1A1AC6B30422DD01D8972323B11BC40756AC8A259DDAD694B57D3CF896C

Node.js

const crypto = require("crypto");

function generateHash(payload, secretKey) {
  const baseString = Object.keys(payload)
    .sort()
    .map((key) => `${key}=${payload[key]}`)
    .join("~");
  return crypto
    .createHash("sha256")
    .update(baseString + secretKey)
    .digest("hex")
    .toUpperCase();
}

Python

import hashlib

def generate_hash(payload: dict, secret_key: str) -> str:
    base = "~".join(f"{k}={payload[k]}" for k in sorted(payload))
    return hashlib.sha256((base + secret_key).encode()).hexdigest().upper()

1 · Payment Request

POST/api/v1/payin/paymentrequest

Form-urlencoded. Creates the order; browser follows 302 Location to hosted checkout.

FieldTypeReqDescription
PAY_IDStringYesMerchant Pay ID
ORDER_IDStringYesUnique order ID
AMOUNTStringYesINR amount (e.g. 100 or 12.50)
TXNTYPEStringYesSALE
CURRENCY_CODEStringYes356 (INR)
RETURN_URLStringYesCustomer return URL
CUST_NAMEStringYesCustomer name
CUST_EMAILStringYesCustomer email
CUST_PHONEStringYesCustomer mobile
CUST_STREET_ADDRESS1StringNoAddress
CUST_ZIPStringNoPostal code
USER_IDStringNoYour user id
ORDER_DESCStringNoDescription
HASHStringYesSHA-256 uppercase signature

cURL

curl --location '{BASE_URL}/api/v1/payin/paymentrequest' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'PAY_ID=1766566497559252' \
  --data-urlencode 'ORDER_ID=TTO2025043342312951' \
  --data-urlencode 'AMOUNT=100' \
  --data-urlencode 'TXNTYPE=SALE' \
  --data-urlencode 'RETURN_URL=https://yoursite.com/payment/response' \
  --data-urlencode 'CUST_NAME=test' \
  --data-urlencode 'USER_ID=20591696' \
  --data-urlencode 'CUST_EMAIL=test@gmail.com' \
  --data-urlencode 'CUST_PHONE=7417006565' \
  --data-urlencode 'CUST_STREET_ADDRESS1=Test' \
  --data-urlencode 'CUST_ZIP=TWQ123' \
  --data-urlencode 'ORDER_DESC=Payin' \
  --data-urlencode 'CURRENCY_CODE=356' \
  --data-urlencode 'HASH=018BC1A1AC6B30422DD01D8972323B11BC40756AC8A259DDAD694B57D3CF896C'

Request body

{
  "PAY_ID": "1766566497559252",
  "ORDER_ID": "TTO2025043342312951",
  "AMOUNT": "100",
  "TXNTYPE": "SALE",
  "RETURN_URL": "https://yoursite.com/payment/response",
  "CUST_NAME": "test",
  "USER_ID": "20591696",
  "CUST_EMAIL": "test@gmail.com",
  "CUST_PHONE": "7417006565",
  "CUST_STREET_ADDRESS1": "Test",
  "CUST_ZIP": "TWQ123",
  "ORDER_DESC": "Payin",
  "CURRENCY_CODE": "356",
  "HASH": "018BC1A1AC6B30422DD01D8972323B11BC40756AC8A259DDAD694B57D3CF896C"
}

Response (302)

HTTP/1.1 302 Found
Location: {BASE_URL}/checkout/{TXN_ID}

2 · Status Enquiry

POST/api/v1/payin/statusenquiry

JSON. Success: RESPONSE_CODE=000, STATUS=Captured — credit TOTAL_AMOUNT. Verify before fulfilment.

FieldTypeReqDescription
PAY_IDStringYesMerchant Pay ID
ORDER_IDStringYesSame ORDER_ID as creation
AMOUNTStringYesOriginal amount
TXNTYPEStringYesSTATUS
CURRENCY_CODEStringYes356
HASHStringYesSHA-256 uppercase signature

cURL

curl --location '{BASE_URL}/api/v1/payin/statusenquiry' \
  --header 'Content-Type: application/json' \
  --data '{
    "PAY_ID": "9323643809301818",
    "ORDER_ID": "BB1659612317376",
    "AMOUNT": "10000",
    "TXNTYPE": "STATUS",
    "CURRENCY_CODE": "356",
    "HASH": "86A3E529A3A73E0EC886700E44ECFA113C4E39FFCECD80F09C95D341A39DE0F2"
  }'

Request body

{
  "PAY_ID": "9323643809301818",
  "ORDER_ID": "BB1659612317376",
  "AMOUNT": "10000",
  "TXNTYPE": "STATUS",
  "CURRENCY_CODE": "356",
  "HASH": "86A3E529A3A73E0EC886700E44ECFA113C4E39FFCECD80F09C95D341A39DE0F2"
}

Response body

{
  "RESPONSE_DATE_TIME": "2022-08-04T11:35:42.991Z",
  "SURCHARGE_FLAG": "N",
  "AMOUNT": 10000,
  "TOTAL_AMOUNT": 10000,
  "CUST_NAME": "David",
  "CUST_EMAIL": "david@gmail.com",
  "CUST_PHONE": "9998887777",
  "CURRENCY_CODE": "356",
  "MOP_TYPE": "UPI",
  "ORDER_ID": "BB1659612317376",
  "PAYMENT_TYPE": "UPI",
  "PAY_ID": "9323643809301818",
  "RRN": "123456789101",
  "RESPONSE_CODE": "000",
  "ORDER_DESC": "",
  "TXNTYPE": "Status",
  "TXN_ID": "4694e5ce-b8cd-475a-82b9-eec7bb846367",
  "CARD_MASK": "0123456789@ybl",
  "PG_REF_NUM": "9e4f41a5-3955-4fe1-9c1b-421c83ff0c25",
  "ORIG_TXN_ID": "4694e5ce-b8cd-475a-82b9-eec7bb846367",
  "STATUS": "Captured",
  "RESPONSE_MESSAGE": "SUCCESS",
  "HASH": "8EAC6B6DC198A6B3DCA18995B0843A2A9D305825906261E0E34B425C7329DEBC"
}

3 · Callback

POST{Callback_URL}

We POST status changes to your webhook. Verify HASH, then respond { "STATUS": "TRUE" }.

cURL (simulate callback)

curl --location --request POST 'https://yoursite.com/payment/callback' \
  --header 'Content-Type: application/json' \
  --data '{
    "RESPONSE_DATE_TIME": "2022-08-04T11:35:42.991Z",
    "AMOUNT": 10000,
    "TOTAL_AMOUNT": 10000,
    "ORDER_ID": "BB1659612317376",
    "PAY_ID": "9323643809301818",
    "RESPONSE_CODE": "000",
    "STATUS": "Captured",
    "RESPONSE_MESSAGE": "SUCCESS",
    "TXN_ID": "4694e5ce-b8cd-475a-82b9-eec7bb846367",
    "HASH": "8EAC6B6DC198A6B3DCA18995B0843A2A9D305825906261E0E34B425C7329DEBC"
  }'

Payload we send

{
  "RESPONSE_DATE_TIME": "2022-08-04T11:35:42.991Z",
  "SURCHARGE_FLAG": "N",
  "AMOUNT": 10000,
  "TOTAL_AMOUNT": 10000,
  "CUST_NAME": "David",
  "CUST_EMAIL": "david@gmail.com",
  "CUST_PHONE": "9998887777",
  "CURRENCY_CODE": "356",
  "MOP_TYPE": "UPI",
  "ORDER_ID": "BB1659612317376",
  "PAYMENT_TYPE": "UPI",
  "PAY_ID": "9323643809301818",
  "RRN": "123456789101",
  "RESPONSE_CODE": "000",
  "ORDER_DESC": "",
  "TXNTYPE": "Status",
  "TXN_ID": "4694e5ce-b8cd-475a-82b9-eec7bb846367",
  "CARD_MASK": "0123456789@ybl",
  "PG_REF_NUM": "9e4f41a5-3955-4fe1-9c1b-421c83ff0c25",
  "ORIG_TXN_ID": "4694e5ce-b8cd-475a-82b9-eec7bb846367",
  "STATUS": "Captured",
  "RESPONSE_MESSAGE": "SUCCESS",
  "HASH": "8EAC6B6DC198A6B3DCA18995B0843A2A9D305825906261E0E34B425C7329DEBC"
}

Your ack

{ "STATUS": "TRUE" }

Response codes

Status

CodeStatus
000Captured
003Timeout
004Declined
005Pending
007Rejected
008Duplicate
010Cancelled
012Denied due to fraud
022Failed at Acquirer
026Denied by risk
027Sent to Bank
028Invalid
029Failed
030Settled
031Refund Captured
032Refund Initiated
034User Cancelled

Errors

CodeMessage
300Invalid Request
500Internal system error
999Unknown Error
429Too Many Concurrent Requests, Retry
098User Blocked

HTTP 429: wait 1s, retry up to 3 times.

Need credentials?

Complete merchant onboarding to receive PAY_ID, secret keys, and environment base URLs.