Record the card a completed SetupIntent saved
const url = 'https://api.aerandil.com/v1/persons/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/payment-cards';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"capture_kind":"terminal","reservation_id":"2489E9AD-2EE2-8E00-8EC9-32D5F69181C0","retain_until":"2026-04-15","setup_intent_id":"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://api.aerandil.com/v1/persons/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/payment-cards \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "capture_kind": "terminal", "reservation_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "retain_until": "2026-04-15", "setup_intent_id": "example" }'Takes the SetupIntent id — never the card’s details — and reads the brand, last four, expiry, funding and wallet back off the processor, because a page that collected the card could otherwise claim any brand and last four it liked. What the caller does supply is the pair of facts the processor cannot know: how the card was captured (Stripe cannot tell a guest typing on their own phone from an agent typing at the counter, and the difference decides chargeback liability) and how long this jurisdiction says it may be kept.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”The guest the card binds to.
Header Parameters
Section titled “Header Parameters”Opaque idempotency token (Stripe-shape). Repeated POSTs with the same key replay the original response within the cache TTL rather than creating a duplicate object.
Request Bodyrequired
Section titled “Request Bodyrequired”object
How the card reached the processor. The desk knows this and the processor does not, and the difference decides interchange, chargeback liability, and whether SCA was satisfied.
The booking this card also guarantees, when it does.
Storage-limitation clock. The desk’s jurisdiction decides it.
The SetupIntent the browser just completed. Not the card’s details — those are read back from the processor.
Responses
Section titled “Responses”The card is on file. The response carries the display triple and nothing else — the token is payment.token-marked and this route is not the way around that.
object
For a wallet card this is the device account number’s last four, not the funding card’s — the desk must say so rather than read it out as the guest’s card.
Example
{ "brand": "visa", "wallet": "apple_pay"}Headers
Section titled “Headers”Always no-store. Object and link state is live data and is never cacheable.
The bearer authenticated but does not hold the scope this operation requires.
Structured error wrapper. Every non-2xx response from any Aerandil endpoint serialises to this shape; the HTTP status carries the failure class (4xx/5xx), the body adds a stable code for programmatic dispatch plus a human-readable message.
object
object
Stable, programmatic error code (e.g. unauthorized, forbidden, not_found, invalid_body, invalid_url, precondition_failed, no_secondary_key). Clients dispatch on code, not on the message (which may be localised or contextualised in future versions).
Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.
Human-readable explanation of the failure.
Per-error structured detail. The shape varies by code (e.g. forbidden_action carries {"action": "..."}; precondition_failed carries {"current_version": N}).
Examplegenerated
{ "error": { "code": "example", "instance_id": "example", "message": "example", "parameters": "example" }}No such object in the caller’s tenant — which is also the answer when it exists in another tenant, by design.
Structured error wrapper. Every non-2xx response from any Aerandil endpoint serialises to this shape; the HTTP status carries the failure class (4xx/5xx), the body adds a stable code for programmatic dispatch plus a human-readable message.
object
object
Stable, programmatic error code (e.g. unauthorized, forbidden, not_found, invalid_body, invalid_url, precondition_failed, no_secondary_key). Clients dispatch on code, not on the message (which may be localised or contextualised in future versions).
Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.
Human-readable explanation of the failure.
Per-error structured detail. The shape varies by code (e.g. forbidden_action carries {"action": "..."}; precondition_failed carries {"current_version": N}).
Examplegenerated
{ "error": { "code": "example", "instance_id": "example", "message": "example", "parameters": "example" }}card_not_collected — the intent has saved no card yet, because the guest has not completed the form; invalid_setup_intent_id — the id is not shaped seti_ plus letters and digits, refused before the processor is asked; setup_intent_mismatch — the processor answered with another intent.
Structured error wrapper. Every non-2xx response from any Aerandil endpoint serialises to this shape; the HTTP status carries the failure class (4xx/5xx), the body adds a stable code for programmatic dispatch plus a human-readable message.
object
object
Stable, programmatic error code (e.g. unauthorized, forbidden, not_found, invalid_body, invalid_url, precondition_failed, no_secondary_key). Clients dispatch on code, not on the message (which may be localised or contextualised in future versions).
Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.
Human-readable explanation of the failure.
Per-error structured detail. The shape varies by code (e.g. forbidden_action carries {"action": "..."}; precondition_failed carries {"current_version": N}).
Examplegenerated
{ "error": { "code": "example", "instance_id": "example", "message": "example", "parameters": "example" }}No card rail is configured on this deployment.
Structured error wrapper. Every non-2xx response from any Aerandil endpoint serialises to this shape; the HTTP status carries the failure class (4xx/5xx), the body adds a stable code for programmatic dispatch plus a human-readable message.
object
object
Stable, programmatic error code (e.g. unauthorized, forbidden, not_found, invalid_body, invalid_url, precondition_failed, no_secondary_key). Clients dispatch on code, not on the message (which may be localised or contextualised in future versions).
Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.
Human-readable explanation of the failure.
Per-error structured detail. The shape varies by code (e.g. forbidden_action carries {"action": "..."}; precondition_failed carries {"current_version": N}).
Examplegenerated
{ "error": { "code": "example", "instance_id": "example", "message": "example", "parameters": "example" }}rail_unavailable — the card processor could not be reached (a transport failure, a 5xx, a 429, or this request’s key still running at the processor). The card was not stored. Try again after Retry-After.
Structured error wrapper. Every non-2xx response from any Aerandil endpoint serialises to this shape; the HTTP status carries the failure class (4xx/5xx), the body adds a stable code for programmatic dispatch plus a human-readable message.
object
object
Stable, programmatic error code (e.g. unauthorized, forbidden, not_found, invalid_body, invalid_url, precondition_failed, no_secondary_key). Clients dispatch on code, not on the message (which may be localised or contextualised in future versions).
Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.
Human-readable explanation of the failure.
Per-error structured detail. The shape varies by code (e.g. forbidden_action carries {"action": "..."}; precondition_failed carries {"current_version": N}).
Examplegenerated
{ "error": { "code": "example", "instance_id": "example", "message": "example", "parameters": "example" }}Headers
Section titled “Headers”Seconds to wait before trying the same request again (RFC 9110 §10.2.3) — the queue’s first backoff.