Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.zennopay.in/llms.txt

Use this file to discover all available pages before exploring further.

This walks through the minimum a partner backend needs to do to create a payment intent and hand it off to the Zennopay SDK on mobile.
Sandbox keys and JWKS endpoint are issued manually during onboarding for v1. Email partners@zennopay.com to receive a sandbox key ID and signing secret.

1. Get your credentials

You will receive:
  • A key ID (e.g. wizz_sandbox_2026q2) and a 32-byte signing secret for HMAC-signed API calls.
  • A JWKS endpoint URL you publish on your own domain (https://your-domain/.well-known/jwks.json), containing the RS256 public key your backend uses to sign session JWTs.
See Authentication for the full key-management model.

2. Sign and send your first API call

Construct the canonical request string, HMAC-SHA256 it with your signing secret, and send it with the four required headers.
curl -X POST https://api.zennopay.com/v1/payment_intents \
  -H "X-Zennopay-Key-Id: wizz_sandbox_2026q2" \
  -H "X-Zennopay-Timestamp: 2026-05-21T14:30:00Z" \
  -H "X-Zennopay-Nonce: a1b2c3d4e5f6789012345678abcdef00" \
  -H "X-Zennopay-Signature: <base64_hmac_sha256>" \
  -H "Content-Type: application/json" \
  -d '{"amount_usd_cents":345,"corridor":"th_promptpay"}'
You should receive a 200 OK with an intent_id:
{
  "intent_id": "zp_AbCd1234EfGh5678",
  "status": "created",
  "amount_usd_cents": 345,
  "corridor": "th_promptpay"
}

3. Mint a session JWT

Sign a JWT with your RS256 private key that authorizes one user to complete one intent. The session expires in 10 minutes max.
{
  "iss": "https://api.your-domain.com",
  "aud": "zennopay-checkout",
  "sub": "your_user_id_xyz",
  "iat": 1716305400,
  "exp": 1716305700,
  "jti": "0190a8b3-4c5d-7e6f-8a9b-c0d1e2f3a4b5",
  "zennopay:intent_id": "zp_AbCd1234EfGh5678",
  "zennopay:amount_usd_cents": 345,
  "zennopay:corridor": "th_promptpay",
  "zennopay:kyc_attestation": {
    "verified": true,
    "method": "your_kyc_v2",
    "verified_at": "2026-05-21T13:30:00Z"
  },
  "zennopay:sanctions_attestation": {
    "clean": true,
    "screened_at": "2026-05-21T14:25:00Z"
  }
}
Full claim documentation is in Authentication → JWT claims.

4. Hand off to the mobile SDK

Pass the intent_id and jwt to the Zennopay SDK on the user’s device:
Zennopay.openCheckout(
  intentID: "zp_AbCd1234EfGh5678",
  jwt: "eyJhbGciOi...",
  returnScheme: "yourapp"
)
The SDK opens a Zennopay-hosted checkout, the user scans + confirms, and the SDK returns control to your app with a result callback. See the platform-specific guides for the full SDK lifecycle:

iOS SDK

Android SDK

5. Receive the webhook

After the payment settles (or fails), Zennopay POSTs a signed webhook to your configured endpoint. See Webhooks for the payload shape and signature verification steps.

Common errors

HTTPerror.codeLikely cause
401authentication_failedBad HMAC signature, expired timestamp, replayed nonce, or IP not in allowlist
401jwt_invalidJWT signature, audience, expiry, or jti (replay) check failed
400invalid_corridorCorridor must be th_promptpay or vn_vietqr
422amount_below_minimumMinimum transaction value not met for the corridor
All 401s use a generic message in the response body. Use the request_id field to correlate with internal logs when contacting support.