Skip to content

Top up an in-house stay's card hold now

POST
/v1/stays/{stay_id}/holds/top-up
curl --request POST \
--url https://api.aerandil.com/v1/stays/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/holds/top-up \
--header 'Authorization: Bearer <token>'

OPERA’s “Run Additional Authorization”: the top-up the stay’s bill calls for now (plan_hold_top_up with on_demand) — the bill’s balance, less what the stay’s pending holds hold, plus the allowance of the incidental-hold rule its booking matches — carried out as the night audit would, whatever the house’s threshold and never past its max_per_stay: a second hold for the excess on the card the stay’s hold was taken on, off-session (the card must carry the guest’s consent to charges the house initiates), or the hold raised in place where the card and the account allow incremental authorisation; past the credit limit at a house that charges (set_credit_limit_overage), the holds taken for the bill and the allowance held afresh. A decline, an authentication demand, the house’s merchant account not ready and an attempt the rail had to give up are outcomes, not errors: 200 with outcome = refused and the reason, recorded on the stay for the desk (hold_top_up.refused). Stripe unreachable (since 2026-10-21): the stay’s open attempt is queued for the card rail — 202, a rail_instruction of kind top_up — and carried out by its drain under the attempt’s own processor keys; a press while it is queued answers the same instruction. Needs the catch-all actions:apply or the route’s own grant. 501 unless AERANDIL_STRIPE_ENABLED=1.

stay_id
required
string format: uuid

The in-house stay whose card hold is topped up.

Idempotency-Key
string
>= 1 characters

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.

What the rail did: nothing (with the reason), a hold placed or raised, the holds taken for the bill, or a refusal with its reason.

Media typeapplication/json
object
amount
string | null format: decimal
captured
string | null format: decimal
currency
string | null
idempotent_replay
boolean
outcome
required
string
Allowed values: nothing placed incremented charged refused
payment_id
string | null format: uuid
reason
string | null
refusal
string | null
Allowed values: card_declined insufficient_funds authentication_required no_consent no_card max_reached other_currency processor_refused attempt_abandoned
refusal_detail
string | null
stay_id
required
string format: uuid
Example
{
"outcome": "nothing",
"refusal": "card_declined"
}
Cache-Control
string

Always no-store. Object and link state is live data and is never cacheable.

Stripe could not be reached (a transport failure, a 5xx, a 429, or this attempt’s key still running at Stripe), so the work was written down as a rail instruction and is taken when the rail is back — under the same processor key as this attempt, so it is never taken twice. A second request while it is queued answers the same instruction (already_queued); the desk may cancel it while it is still queued (cancel_rail_instruction).

Media typeapplication/json
object
already_queued
boolean
amount
string | null format: decimal
currency
string | null
idempotent_replay
boolean
kind
required
string
Allowed values: capture void refund charge_off_session top_up
message
string
payment_id
string | null format: uuid
queued
required
boolean
rail_instruction_id
required
string format: uuid
state
required
string
Allowed values: queued sending
stay_id
string | null format: uuid
Example
{
"kind": "capture",
"queued": true,
"state": "queued"
}
Cache-Control
string

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.

Media typeapplication/json

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
error
required
object
code
required

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

string
instance_id

Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.

string
message
required

Human-readable explanation of the failure.

string
parameters

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.

Media typeapplication/json

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
error
required
object
code
required

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

string
instance_id

Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.

string
message
required

Human-readable explanation of the failure.

string
parameters

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"
}
}

idempotency_in_flight — a request under this Idempotency-Key is still running; retry shortly. Or rail_instruction_open — another verb is already queued for this hold or stay; it is taken first.

Media typeapplication/json

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
error
required
object
code
required

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

string
instance_id

Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.

string
message
required

Human-readable explanation of the failure.

string
parameters

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"
}
}

stay_not_in_house — only an in-house stay’s hold is topped up; or idempotency_key_mismatch — the key was used for another stay’s top-up.

Media typeapplication/json

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
error
required
object
code
required

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

string
instance_id

Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.

string
message
required

Human-readable explanation of the failure.

string
parameters

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.

Media typeapplication/json

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
error
required
object
code
required

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

string
instance_id

Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.

string
message
required

Human-readable explanation of the failure.

string
parameters

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 — Stripe could not be reached and no top-up attempt was open on the stay, so nothing reached it: try again (Retry-After). With an attempt open the press is queued instead (202).

Media typeapplication/json

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
error
required
object
code
required

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

string
instance_id

Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.

string
message
required

Human-readable explanation of the failure.

string
parameters

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"
}
}
Retry-After
integer

Seconds to wait before trying the same request again (RFC 9110 §10.2.3) — the queue’s first backoff.