Payments Academy

API Playground

Fictional reference API for learning, not a real bank API. There is no real provider behind these examples and no real base URL. Do not copy these payloads into a real integration: every real bank documents its own provider, version, authentication, idempotency and error rules, and they differ by provider.

Try payment API requests and responses against that fictional reference API. Pick an endpoint, read the request, then send a valid request and an invalid one to see how validation and errors work. Every example follows the same payment: USD 25,000 from Northgate Trading Ltd, London, to Tanaka Trading Pte Ltd, Singapore, end to end reference INV-8841. Correspondent charges are USD 20 + USD 22 = USD 42, so the beneficiary is expected to receive USD 24,958.00, matching the accounting simulator for the same payment.

Assumptions of this fictional reference API

  • Base URL (fictional). https://api.example-bank.test/v1 (.test is a reserved domain that never resolves, so no request here can reach a real system).
  • Versioning. The version is in the path (/v1). A new version is a new path (/v2); the provider publishes a changelog and a sunset date, and old versions keep working until that date. This is a teaching assumption, not a rule every provider follows.
  • Authentication and authorisation. OAuth 2.0 bearer tokens, shown as Authorization: Bearer <access_token>, with a scope per operation (payments:read, payments:write). Mutual TLS and certificate-based client authentication, as used by real open-banking APIs, are assumed but not shown. No request in this playground is unauthenticated.
  • Asynchronous processing. Creating, cancelling or enquiring about a payment returns 202 Accepted: the request was accepted for processing. Settlement, beneficiary credit and the final outcome always arrive later, by status enquiry or webhook. An HTTP success never means the payment settled or the beneficiary was credited.
  • Idempotency. Every POST that changes something requires an Idempotency-Key header. Same key with the same body replays the original response; same key with a different body is 409 Conflict. Retries use the same key.
  • Correlation. Every request carries X-Request-ID and every response echoes it, so a request can be traced in the bank’s logs.
  • Timeouts and retries. If a request times out, do not simply resend a POST. Retry with the same Idempotency-Key so the bank returns the original response instead of executing twice. How long to wait before retrying is set by the provider.
  • Rate limits. The provider limits how many requests a caller may make. Exceeding the limit returns 429 Too Many Requests with a Retry-After value; the caller must wait that long before retrying.
  • Errors. Every error response carries an HTTP status, a business error code and a human-readable message. See the error catalogue below: schema errors, business errors and authentication errors are different things and carry different statuses.

POST POST /v1/payments

Creates a new customer credit transfer instruction. The caller supplies debtor, creditor, amount, currency and value date, and the API returns a payment identification that can be used to track the payment. The response only confirms the instruction was accepted for processing: it does not mean the payment has settled or the beneficiary has been credited.

Request headers

Authorization: Bearer <access_token> (OAuth 2.0, scope payments:write)
X-Request-ID: REQ-20261105-0001
Idempotency-Key: IDEM-8841
Content-Type: application/json

Request

{
  "debtor_name": "Northgate Trading Ltd",
  "debtor_account": "GB29NWBK60161331926819",
  "debtor_agent_bic": "NWBKGB2L",
  "creditor_name": "Tanaka Trading Pte Ltd",
  "creditor_address": {
    "street": "1 Harbourfront Avenue",
    "town": "Singapore",
    "postcode": "098633",
    "country": "SG"
  },
  "creditor_account": {
    "bank_name": "DBS Bank Ltd, Singapore",
    "bank_code": "7171",
    "branch_code": "001",
    "account_number": "1234567",
    "note": "Singapore has no IBAN. Singapore accounts are identified by bank code + branch code + account number, not by IBAN."
  },
  "creditor_agent_bic": "DBSSSGSG",
  "currency": "USD",
  "amount": 25000.0,
  "value_date": "2026-11-05",
  "remittance_information": "INV-8841",
  "end_to_end_id": "INV-8841",
  "charge_bearer": "SHA",
  "fx_quote_id": "FXQ-20261105-5510"
}

Validation rules

  • An Idempotency-Key header is required on this POST. The same key with the same body replays the original 202 response; the same key with a different body is rejected with 409 Conflict, so a retry can never double-pay.
  • Authorization: Bearer access token (OAuth 2.0) with scope payments:write. A missing or expired token is 401 Unauthorized; a token without the scope is 403 Forbidden.
  • X-Request-ID is required on every request and is echoed on every response, so a request can be traced in the bank's logs.
  • Debtor name, debtor account and debtor agent BIC are required, and the creditor address is required for screening.
  • Creditor account: Singapore has no IBAN, so the account is given as bank code 7171 + branch code 001 + account number. A Singapore account written as an IBAN (for example SG71...) is invalid and fails validation.
  • Amount must be greater than zero and use no more than two decimal places for USD.
  • Currency must be a valid three letter ISO 4217 code, such as USD, EUR or GBP.
  • Value date must be a business day for the payment currency and not in the past.
  • end_to_end_id INV-8841 is the debtor's reference for this payment and stays the same through the whole chain; the UETR is assigned by the bank and returned in the response.
  • fx_quote_id is optional. When supplied, the rate from that quote is the rate applied.

Success response: HTTP 202 Accepted. 202 Accepted means the bank accepted the instruction for processing. It does NOT mean the payment settled or the beneficiary was credited. The payment then moves ACCP, ACSP, ACSC, ACCC, and only ACCC confirms the creditor's account was credited.

Error response: HTTP 422 Unprocessable Content. 422 means the request was well formed but failed a business validation rule (here the creditor account). No payment was created and nothing was debited.

Error catalogue: HTTP status is not the payment status

An HTTP status says what happened to the request. The payment’s own status (ACCP, ACSP, ACSC, ACCC, RJCT, PDNG) says what happened to the payment, and it is always reported separately, in the response body and in the status history. A 202 Accepted response never means the payment settled or the beneficiary was credited.

HTTP statusMeaningBusiness code (example)When it appears here
200 OKRequest succeeded; the response carries the result.—Validation, retrieve payment, retrieve status, FX quote, list. Also what your system returns for a good webhook delivery.
201 CreatedA new resource was created synchronously and its location is returned.—Not used by this reference API: payment creation is asynchronous, so it returns 202, not 201.
202 AcceptedThe request was accepted for processing. The outcome arrives later.—Initiate payment, request cancellation, submit an enquiry.
400 Bad RequestThe request is malformed: bad JSON or a wrong field type.INVALID_REQUESTSchema errors. Different from a business rule failure, which is 422.
401 UnauthorizedMissing, expired or invalid credentials.INVALID_TOKEN, INVALID_SIGNATURE (webhook)Bad access token; a webhook whose signature does not match.
403 ForbiddenAuthenticated, but not allowed to do this.INSUFFICIENT_SCOPEA token without the required scope, or a caller asking for someone else’s payment.
404 Not FoundNo resource with that identification exists.NOT_FOUNDRetrieve, status or cancel for an unknown payment_id.
409 ConflictThe request conflicts with the current state.ALREADY_SETTLED, IDEMPOTENCY_KEY_REUSEDCancelling a settled payment; reusing an idempotency key with a different body.
422 Unprocessable ContentWell formed, but a business rule failed.AC01 (invalid account), AMOUNT_LIMIT_EXCEEDEDInvalid creditor account, an FX amount over the daily limit.
429 Too Many RequestsThe caller exceeded the rate limit.RATE_LIMITEDToo many calls. Honour the Retry-After value before retrying.

Payment status codes (ISO 20022) are separate from HTTP statuses. ACTC: technical validation passed. ACCP: accepted for processing (earlier acceptance). ACSP: accepted, settlement in process (later acceptance). ACSC: settlement completed on the debtor’s account. ACCC: settlement completed on the creditor’s account, the only code that confirms the beneficiary was credited. RJCT: rejected. PDNG: pending. “ACCEPTED” and “CANCELLED” are not ISO 20022 status codes and are never used here.