About the API
Base URL, conventions, and the stability promise behind every endpoint
The pages in this section are generated directly from the Coinland Pay OpenAPI document, so they describe exactly what each endpoint accepts and returns. The document itself is published at /openapi.json if you want to generate a client, a mock server or types from it.
This section is English in both locales
These pages are generated from docs/openapi/pay.v1.yaml, whose contract text is English. Field
names, error codes and paths are English regardless of locale and are never translated; the
conceptual guides, which are translated, are what explain them.
What is documented here is what your integration calls. Setup is not: your API keys, your accepted coins, your branding and your webhook URL are all managed in the business console, which is the only surface with the whole lifecycle for any of them, so you will not find endpoints for them here.
Base URL
https://my.coinlandexchange.comEvery Pay endpoint sits under /api/pay/v1. There is one host and one environment: a session you create
is a session a real customer can pay. See Going live for how to rehearse safely.
Authentication
One header on every request:
Authorization: Bearer clpay_live_<64 hex>Keys are minted and revoked in the business console and shown once at creation. Any auth-layer refusal --
a missing header, a malformed key, a revoked key, an unknown key -- answers the single code
UNAUTHORIZED (401), so a caller cannot probe which part was wrong.
Conventions
Requests and responses are JSON; send Content-Type: application/json on anything with a body.
Amounts are decimal strings. "24.90", never 24.9. This holds for amount, fee_amount and
net_amount, in requests and responses alike. Keep them as strings until they reach a decimal type in
your own code.
Timestamps are RFC 3339, UTC. expires_at, created_at, paid_at, and the from/to filters.
Ids come in two shapes, and both are usable as lookup keys. Sessions and payments carry UUIDs, but
GET /sessions/{id} also accepts your own reference_id, and GET /payments/{id} also accepts a
receipt number (CLP-...). You can therefore read either object without having stored anything Coinland
generated.
Lists are cursor-paginated, newest first. Pass limit and cursor, then follow next_cursor until
it comes back null. Do not count pages or assume a page size.
Idempotency lives on reference_id. There is no Idempotency-Key header. Retrying
POST /sessions with the same reference_id and an identical payload returns the original session; a
different payload with the same id is refused with PAY_DUPLICATE_REFERENCE. See
Sessions.
A not-found and a not-yours answer identically. PAY_SESSION_NOT_FOUND (404) covers both, because a
different answer for "exists but belongs to another business" would let anyone with a key enumerate other
businesses' orders.
Stability
The API is versioned in the path at /v1. Within a version, changes are additive: new endpoints, new
optional request fields and new response properties can appear without notice, and existing fields do not
change meaning or disappear. Anything incompatible ships as a new version, and /v1 keeps working.
Do not use strict object mappers
Because new response properties can appear at any time, a deserializer configured to throw on unknown keys will break on a routine, backwards-compatible change. Configure yours to ignore what it does not recognise.
The same applies to enumerated values. New error codes and new webhook event types are additive, so always have a default branch.
Reliability
Retry a timeout with the same reference_id; that is what idempotency is for. Back off with jitter on a
429. Every failure uses one envelope -- see Errors.
Where to start
Sessions is the endpoint set every integration needs. GET /me is the first call
worth making, because it tells you which coins you may price in.