cardData (full card JSON) with AES-256-GCM using your secret key as key material — do not send the secret key itself in headers. Only when the referenced payment’s currency is NGN, also encrypt and send pin. Then POST cardData, optional pin (NGN only), plain paymentReference, and requestMetadata.
Endpoint
Authentication
Send your dashboard public key in apublic-key header — same key as ApiKey.publicKey in the dashboard. See the S2S Payments overview.
Encrypting card data
Card data fields
Serialize as UTF-8 JSON (minified or pretty). All values are strings.
Example before encryption:
cardData. Only for NGN payments, encrypt the PIN as a separate UTF-8 string and send as pin; omit pin entirely for non-NGN payments. paymentReference is sent in plain text.
Key derivation
Must match the server:- Take the exact secret key string (UTF-8).
- AES-256 key = SHA-256 hash of that string → 32 bytes.
Algorithm
- AES-256-GCM
- IV: 12 random bytes (a new IV for every encryption)
- Auth tag: 16 bytes (GCM tag; required for decryption)
Ciphertext format
Concatenate three hex strings with colons (no spaces):ivHex: 24 hex chars (12 bytes)tagHex: 32 hex chars (16 bytes)cipherHex: variable length
Example (TypeScript, Node.js crypto)
Request body
NGN example
Encrypted card + encrypted PIN + required metadata:Non-NGN example
Encrypted card only, no PIN, required metadata:Minimal example
Encrypted card only, no PIN, metadata unavailable:Response
A
400 on this endpoint specifically means the charge failed (the provider declined it or the encrypted payload couldn’t be decrypted) — distinct from the generic “bad request” meaning elsewhere in this API.Next steps
- Verify a payment order to confirm the final status.
- Webhooks fires
charge.success/charge.failedevents as the charge resolves.