Skip to content

Postman — Hosted Payments

REPLACE EXAMPLE CREDENTIALS

Replace all placeholder values in the pre-request scripts:

  • 'your-api-key' → Your actual API Key from the merchant portal
  • 'your-api-secret' → Your actual API Secret from the merchant portal
  • Replace 1000 in the URL with your actual Merchant ID

How Signatures Work in Postman

Postman's built-in CryptoJS library handles all cryptographic operations. The pre-request scripts below calculate the correct signature and set the required headers automatically before each request.

POST signature: Base64(HMAC-SHA256(timestamp\nPOST\npath\nBase64(SHA256(body)), apiSecret))

GET signature (no query string): Base64(HMAC-SHA256(timestamp\nGET\npath, apiSecret))

GET signature (with query string): Base64(HMAC-SHA256(timestamp\nGET\npath\nBase64(SHA256(queryString)), apiSecret))


Create Order

1. Configure the Request

Method: POSTURL: https://api.paystablecoin.global/api/v1/merchants/1000/orders

Replace 1000 with your Merchant ID.

2. Set the Request Body

In Postman, go to Body → select raw → choose JSON, then paste:

json
{
  "merchantOrderId": "ORDER_{{$timestamp}}",
  "orderAmount": {
    "value": "99.99",
    "currency": "USD"
  },
  "expiresAt": "2026-12-31T23:59:59Z",
  "returnUrl": "https://yoursite.com/payment/success",
  "callbackUrl": "https://yoursite.com/webhook/payment"
}

TIP

is a Postman built-in variable that inserts the current Unix timestamp, ensuring a unique merchantOrderId on every send.

3. Add the Pre-request Script

Go to the Pre-request Script tab and paste the following:

javascript
// ── Configuration ──────────────────────────────────────────────────
const apiKey    = 'your-api-key';
const secretKey = 'your-api-secret';

// ── Timestamp ──────────────────────────────────────────────────────
const timestamp = Date.now().toString();

// ── Request details ────────────────────────────────────────────────
const method = pm.request.method;                 // "POST"
const urlObj = new URL(pm.request.url.toString());
const path   = urlObj.pathname;                   // e.g. /api/v1/merchants/1000/orders

// ── Body: replace Postman variables, then minify ───────────────────
let body = pm.request.body.raw;
body = body.replace(/\{\{\$timestamp\}\}/g, timestamp);
body = JSON.stringify(JSON.parse(body));          // minify
pm.request.body.raw = body;                       // update the actual request body

// ── Body hash: SHA256 → Base64 ─────────────────────────────────────
const bodyHash = CryptoJS.SHA256(body).toString(CryptoJS.enc.Base64);

// ── Build signature string ─────────────────────────────────────────
const stringToSign = [timestamp, method, path, bodyHash].join('\n');

console.log('=== Hosted Payments — Create Order ===');
console.log('Timestamp:', timestamp);
console.log('Method:', method);
console.log('Path:', path);
console.log('Body Hash (Base64):', bodyHash);
console.log('String to Sign:', stringToSign.replace(/\n/g, ' | '));

// ── HMAC-SHA256 → Base64 ───────────────────────────────────────────
const signature = CryptoJS.enc.Base64.stringify(
    CryptoJS.HmacSHA256(stringToSign, secretKey)
);
console.log('Signature:', signature);

// ── Set headers ────────────────────────────────────────────────────
pm.request.headers.upsert({ key: 'Content-Type', value: 'application/json' });
pm.request.headers.upsert({ key: 'X-Api-Key',    value: apiKey });
pm.request.headers.upsert({ key: 'X-Timestamp',  value: timestamp });
pm.request.headers.upsert({ key: 'X-Signature',  value: signature });

4. Send and Verify

Click Send. A successful response looks like:

json
{
  "code": "00000",
  "message": "Success",
  "data": {
    "orderId": "ord_8fcb2a2e5b",
    "merchantOrderId": "ORDER_1738112345000",
    "status": "INIT",
    "checkoutUrl": "https://checkout.paystablecoin.global/ord_8fcb2a2e5b"
  }
}

Redirect the customer to checkoutUrl to complete payment.


Query Order

1. Configure the Request

Method: GETURL: https://api.paystablecoin.global/api/v1/merchants/1000/orders/ORDER_1738112345000

Replace 1000 with your Merchant ID and ORDER_1738112345000 with the order ID to query.

2. No Body Required

Leave the Body tab empty (select none).

3. Add the Pre-request Script

javascript
// ── Configuration ──────────────────────────────────────────────────
const apiKey    = 'your-api-key';
const secretKey = 'your-api-secret';

// ── Timestamp ──────────────────────────────────────────────────────
const timestamp = Date.now().toString();

// ── Request details ────────────────────────────────────────────────
const method = pm.request.method;                 // "GET"
const urlObj = new URL(pm.request.url.toString());
const path   = urlObj.pathname;

// ── Build signature string (no body, no query string) ──────────────
const stringToSign = [timestamp, method, path].join('\n');

console.log('=== Hosted Payments — Query Order ===');
console.log('Timestamp:', timestamp);
console.log('Method:', method);
console.log('Path:', path);
console.log('String to Sign:', stringToSign.replace(/\n/g, ' | '));

// ── HMAC-SHA256 → Base64 ───────────────────────────────────────────
const signature = CryptoJS.enc.Base64.stringify(
    CryptoJS.HmacSHA256(stringToSign, secretKey)
);
console.log('Signature:', signature);

// ── Set headers ────────────────────────────────────────────────────
pm.request.headers.upsert({ key: 'X-Api-Key',   value: apiKey });
pm.request.headers.upsert({ key: 'X-Timestamp', value: timestamp });
pm.request.headers.upsert({ key: 'X-Signature', value: signature });

Query Refund (GET with Query String)

For refund queries, the query string is hashed as the fourth component of the signature.

1. Configure the Request

Method: GETURL: https://api.paystablecoin.global/api/v1/merchants/1000/refunds

Add a Query Param: key refundOrderId, value REF_20260128120001.

2. Add the Pre-request Script

javascript
// ── Configuration ──────────────────────────────────────────────────
const apiKey    = 'your-api-key';
const secretKey = 'your-api-secret';

// ── Timestamp ──────────────────────────────────────────────────────
const timestamp = Date.now().toString();

// ── Request details ────────────────────────────────────────────────
const method = pm.request.method;                 // "GET"
const urlObj = new URL(pm.request.url.toString());
const path   = urlObj.pathname;
const qs     = urlObj.search.replace(/^\?/, '');  // e.g. "refundOrderId=REF_..."

// ── Query string hash: SHA256 → Base64 ────────────────────────────
const qsHash = CryptoJS.SHA256(qs).toString(CryptoJS.enc.Base64);

// ── Build signature string ─────────────────────────────────────────
const stringToSign = [timestamp, method, path, qsHash].join('\n');

console.log('=== Hosted Payments — Query Refund ===');
console.log('Query String:', qs);
console.log('QS Hash (Base64):', qsHash);
console.log('String to Sign:', stringToSign.replace(/\n/g, ' | '));

// ── HMAC-SHA256 → Base64 ───────────────────────────────────────────
const signature = CryptoJS.enc.Base64.stringify(
    CryptoJS.HmacSHA256(stringToSign, secretKey)
);

// ── Set headers ────────────────────────────────────────────────────
pm.request.headers.upsert({ key: 'X-Api-Key',   value: apiKey });
pm.request.headers.upsert({ key: 'X-Timestamp', value: timestamp });
pm.request.headers.upsert({ key: 'X-Signature', value: signature });

Troubleshooting

ErrorLikely CauseFix
Invalid signatureWrong key or body mismatchVerify apiKey/secretKey; check the Console log for the body hash
Invalid or expired timestampClock out of syncSync your system time; timestamp must be within ±5 minutes
Missing required fieldIncomplete request bodyCheck all required fields are present
Invalid parameter: merchantIdWrong Merchant ID in URLVerify the Merchant ID matches your credentials

Released under the MIT License.