Coinland PayDocs
API reference

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.com

Every 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.

On this page