Skip to main content
For merchants handling raw card data on their own server as part of a fully embedded checkout — see Choosing a flow for how this compares to Create a hosted checkout link. Encrypt 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 a public-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:
Encrypt that JSON string and send the result as 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:
  1. Take the exact secret key string (UTF-8).
  2. AES-256 key = SHA-256 hash of that string → 32 bytes.
Never send your secret key itself in a request or header — only the derived ciphertext.

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.
See Errors for the shape of 401/500 responses.

Next steps