Record the channel's virtual card a completed SetupIntent saved
const url = 'https://api.aerandil.com/v1/reservations/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/virtual-cards';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"activation_date":"2026-04-15","funded_amount":{"amount":"example","currency":"example"},"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/reservations/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/virtual-cards \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "activation_date": "2026-04-15", "funded_amount": { "amount": "example", "currency": "example" }, "retain_until": "2026-04-15", "setup_intent_id": "example" }'Takes the SetupIntent id and the channel’s terms, never the card’s details: the intent must carry this deployment’s tags for this booking (setup_intent_not_for_this_booking otherwise) and the merchant account the house settles to now — none when it has none (setup_intent_not_for_this_account otherwise) — and have succeeded, and the card is read back off Stripe and must hang off the intent’s own Customer (card_belongs_to_another_customer). Recorded through the card rail’s verb record_saved_payment_card as card_format: virtual, bound to the booking, with the Customer — the one way a virtual card gets the Customer its off-session activation charge needs. A token handed in through the public store_payment_card names no Customer and is refused at activation.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”The booking the channel’s card was funded for.
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
The first day the channel lets the house charge the card (the house’s calendar); the activation charge sweeps it from the house’s midnight on it.
object
Exact decimal as a string. Money is never a float — binary floating point cannot hold 0.10.
Storage-limitation clock.
The SetupIntent from POST /v1/reservations/{reservation_id}/virtual-card-setup-intents the desk completed with the channel’s card.
Examplegenerated
{ "activation_date": "2026-04-15", "funded_amount": { "amount": "example", "currency": "example" }, "retain_until": "2026-04-15", "setup_intent_id": "example"}Responses
Section titled “Responses”The channel’s card is on file for the booking. The display triple only; the token is payment.token-marked.
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" }}invalid_setup_intent_id (not shaped seti_ plus letters and digits; refused before the processor is asked), setup_intent_mismatch, setup_intent_not_for_this_booking, setup_intent_not_for_this_account (minted while the house settled to a different merchant account than it does now), card_not_collected or card_belongs_to_another_customer; or the channel’s terms refused (funded_amount not positive).
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 channel’s 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.