IdealBoxPay

Documentation

Take your first payment.

Everything below is the real contract: the routes, the statuses, the failure codes, and the rules a correct integration follows.

Money is a string of minor units

Always paired with its currency, always a decimal string. "1050" in USD is $10.50; "500000" in XAF is five hundred thousand francs, because XAF has no minor unit at all. The exponent belongs to the currency and nowhere else.

Dates are epoch milliseconds

Every timestamp in every response, on both REST and GraphQL. No ISO strings, no timezone to get wrong, no format to parse.

Identifiers are prefixed

Every id you ever see is a prefixed ULID. The prefix says what the object is, which makes a log line readable and a mis-passed id obvious at the call site rather than three functions later.

pi_

A payment — the instruction to collect.

ch_

One attempt against one provider.

cus_

A payer you have named.

wlt_

A container separating one product’s money from another’s.

evt_

A domain event, before delivery.

ak_

An API credential.

Idempotency

Send an Idempotency-Key on anything that moves money. Networks time out and clients retry; without a replay guard the customer is charged twice.

# The same key twice returns the FIRST result — it does not charge twice.
KEY=$(uuidgen)

curl https://api.idealbox.org/v1/payment_intents -H "Idempotency-Key: $KEY" …   # 201
curl https://api.idealbox.org/v1/payment_intents -H "Idempotency-Key: $KEY" …   # 201, same payment

# The same key with a DIFFERENT body is a client bug, and is refused:
# 412 idempotency_key_reused

Pagination

One envelope everywhere: items, total, page, limit and hasMore, capped at a hundred per page. Read hasMore from the response rather than computing it — page × limit versus total disagree the moment a row is inserted between the count and the fetch.

curl "https://api.idealbox.org/v1/payment_intents?limit=20&page=1&search=order-4471" \
  -H "Authorization: Bearer ib_sk_test_4f2a9c1e8b7d6053"