Skip to content

Fourteen operations, one signing scheme, and no ambiguity about retries.

The merchant API is machine-to-machine. There are no OAuth redirects and no bearer tokens sitting in a browser — every request is signed, timestamped and single-use.

Read the API reference OpenAPI 3.1 spec

This page is the shape of the contract. The reference is the contract: the canonical string with a worked example, every field of every request and response, every error code, and the webhook payloads.

Required headers
X-Api-Key:    01KA7Y2M6Q4RXHB9WD3F5NTC8V
X-Timestamp:  1787000400
X-Nonce:      f47ac10b-58cc-4372-a567-0e02b2c3d479
X-Signature:  hmac-sha256(secret, canonical)

# plus, on every mutating call:
Idempotency-Key: "<your key>"

Requests are signed, not merely authenticated.

A leaked bearer token is a standing licence to move money. A signed request is not: the signature covers the request, the timestamp bounds it, and the nonce spends it.

Control Behaviour On failure
Signature HMAC-SHA256 over a canonical string, compared in constant time. 401 invalid_signature
Timestamp window Requests outside a 300-second window are rejected. 401 timestamp_out_of_window
Nonce Single-use per key, enforced by a unique constraint. 409 replay_detected
Key state Unknown, revoked or expired keys are refused. 401 invalid_api_key
Rate limit Per key, with Retry-After and X-RateLimit-* headers. 429 exceeded
IP allowlist Optional, configured per API key by the merchant. 403 ip_not_allowed
Scopes Optional, per API key. A route requires at most one. 403 out_of_scope

Gateway error messages are deliberately minimal. The precise reason is carried in the errors object, which is safe to show the authenticated merchant and useless to anyone else.

Retrying is safe by contract, not by luck.

Every mutating financial endpoint requires an Idempotency-Key. It is a required header, not an optional optimisation, and the same key is forwarded to the issuing partner as the client reference — so a retry is deduplicated at both ends, not just at ours.

  • Replaying a key with the same payload returns the original result.
  • Replaying a key with a different payload is rejected, not silently applied.
  • A request still in flight returns 409 rather than starting a second one.
Error envelope
{
  "success": false,
  "message": "Human-readable description.",
  "errors": {
    "idempotency": ["payload_mismatch"]
  }
}
Cursor pagination
{
  "success": true,
  "data": [ /* one page */ ],
  "meta": {
    "per_page":         20,
    "has_more":         false,
    "next_cursor":      null,
    "previous_cursor":  null
  }
}

Cursor, not offset. Merchant tables grow while you are walking them, and an offset page shifts under concurrent inserts — so you would silently skip rows. per_page is clamped to 1–100.

Outgoing webhooks are signed and retried.

Endpoints you register receive HMAC-signed deliveries with retries and backoff. Destinations are validated against server-side request forgery before anything is sent — an endpoint that resolves to internal address space is refused rather than called. Delivery records and payloads are pruned on a retention schedule once terminal.

Signing
HMAC over the delivered payload
Retries
queued, with backoff
Destination check
SSRF guard before dispatch
Dispatch sweep
every minute

Questions the contract answers.

Can I retrieve a full card number?
No. Card numbers and security codes are never exposed through the merchant API and are never persisted. A card resource carries a masked number and its last four digits. Reveal is a separate authenticated-user surface with step-up verification, not a programmatic endpoint.
What identifiers will I see?
Public identifiers are 26-character ULIDs. Internal database ids, provider ids and provider references never leave the system.
Why did an issue call return 202 instead of 201?
Because the issuing partner provisions asynchronously. You receive a card in pending state; poll the card, or wait for the settlement that runs from the partner's webhook or from the reconciliation sweep. Replaying the same idempotency key returns the card in its current state.
Is there a withdrawals endpoint?
No, deliberately. Withdrawals run through the portal with an operator approval step. The one operation that moves money out of the platform is not reachable with an API key.
How long are API request logs kept?
Ninety days by default, then pruned on a daily schedule.

Responsible disclosure.

If you believe you have found a vulnerability, report it through the contact form with the topic set to support, or to the security address published in the Compliance statement once the legal entity details are registered.

We aim to acknowledge a report within two business days. We ask that you do not access, modify or exfiltrate data belonging to anyone else, and that you give us a reasonable window to remediate before publishing. There is no paid bounty programme.

Report an issue

Reference and access.

The full reference is published, and so is the OpenAPI 3.1 specification behind it — the machine-readable contract for all fourteen operations, ready to import into a client generator or a request collection.

Test-mode keys are available in the portal. A test key exercises the same endpoints, the same signing and the same response shapes against a simulated issuer and a segregated wallet of play money — nothing it does touches a real card or a real balance.

Read the API reference Sign in Contact us