Pair a terminal
const url = 'https://terminal.api.example.com/v1/terminal_pairings';const options = { method: 'POST', headers: {'Content-Type': 'application/json'}, body: '{"serial":"TX00000001","pairing_code":"ABCDE-FGH12","csr":"example","attestation_chain":["example"]}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://terminal.api.example.com/v1/terminal_pairings \ --header 'Content-Type: application/json' \ --data '{ "serial": "TX00000001", "pairing_code": "ABCDE-FGH12", "csr": "example", "attestation_chain": [ "example" ] }'Called by the terminal itself, with no API key or Access Token, to exchange its Pairing Code for its client certificate. The key must be generated in the terminal’s hardware-backed Android Keystore with the code’s digest as its attestation challenge: see Pairing a terminal for how.
Every refusal is the same 401 pairing_refused, whichever check failed. Requests are
limited per address. A retry with the same code and key, after a lost answer, returns the
same certificate.
Request Bodyrequired
Section titled “Request Bodyrequired”object
The terminal’s serial number, as the device reports it.
The Pairing Code the operations team issued for this terminal. Case, dashes and spaces make no difference.
A PKCS#10 certificate signing request in PEM, signed by the attested key. Its subject is ignored.
The key’s attestation certificate chain from the Android Keystore, leaf first, each certificate as standard base64 of its DER. The root may be left off.
Responses
Section titled “Responses”The terminal’s certificate. Sent with Cache-Control: no-store.
object
The id of the terminal the certificate is for.
The terminal’s client certificate, in PEM, for its key. Presented over mutual TLS on
the terminal’s later calls. Valid for up to 7 days: expires_at says when it ends.
The certificates above it, in PEM, its issuer first.
When the certificate expires, as a Unix timestamp.
Always true. A terminal is a live device; there are no test terminals.
Example
{ "object": "terminal_pairing", "terminal_id": "3f6c2a9e-8b41-4d7a-9e25-0c1b7d4f8a63", "expires_at": 1790999400, "livemode": true}validation_failure with invalid_parameter: a field is missing or not readable. param names a missing field, or is request when the CSR is not PEM or a chain entry is not base64. Also the codes any /v1 call can get for a body that is not JSON.
object
object
A stable name for this refusal. Branch on this, never on message.
For the developer reading a log. May be reworded.
The field or parameter at fault, when there is one.
Example
{ "error": { "type": "validation_failure" }}authentication_failure with pairing_refused: the same for every refusal, whichever check failed. See Pairing a terminal for what is checked.
object
object
A stable name for this refusal. Branch on this, never on message.
For the developer reading a log. May be reworded.
The field or parameter at fault, when there is one.
Example
{ "error": { "type": "authentication_failure", "code": "pairing_refused", "message": "The pairing was refused. Ask for a new Pairing Code if this one may be spent or expired.", "param": null, "request_id": "req_4f1c0b2e9a7d" }}rate_limited: too many pairing requests from this address. Wait for Retry-After seconds.
object
object
A stable name for this refusal. Branch on this, never on message.
For the developer reading a log. May be reworded.
The field or parameter at fault, when there is one.
Example
{ "error": { "type": "validation_failure" }}dependency_failure with service_unavailable: the platform did not answer, or failed part-way. Whether the terminal was paired is not known. Retry the same request: the same code and key return the same certificate if it was issued, so never make a new key for the retry.
object
object
A stable name for this refusal. Branch on this, never on message.
For the developer reading a log. May be reworded.
The field or parameter at fault, when there is one.
Example
{ "error": { "type": "validation_failure" }}