Skip to content

Open a property's merchant account

POST
/v1/properties/{property_id}/merchant-account
curl --request POST \
--url https://api.aerandil.com/v1/properties/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/merchant-account \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "country": "example", "email": "hello@example.com", "fee_conversion_bps": 1, "fee_schedule": [ { "bps": 1, "card_present": true, "fee_class": "domestic_standard", "fixed": { "amount": "example", "currency": "example" }, "processor_bps": 1, "processor_fixed": { "amount": "example", "currency": "example" } } ], "markup_bps": 1 }'

Creates the hotel’s own Stripe account under the platform’s (Stripe Connect, Express-style: Stripe verifies the hotel on its hosted form, the hotel gets Stripe’s Express dashboard, the platform pays Stripe’s fees) and records it with open_merchant_account. The account opens in onboarding; send the hotel to the onboarding link next. While the account is open but not yet active, card payments at the property are refused with merchant_account_not_ready rather than taken on the platform’s account. If the ledger refuses the account after Stripe has made it, the Stripe account is deleted again. Operator only (tenant_admin:write): the platform signs the hotel up and sets its fee. 501 unless AERANDIL_STRIPE_ENABLED=1.

property_id
required
string format: uuid

The property whose card payments will settle to the account.

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.

Media typeapplication/json
object
country
required

Where the hotel trades (ISO 3166-1 alpha-2). Fixed for the account’s life.

string
email

The hotel’s contact, prefilled on Stripe’s form.

string format: email
fee_conversion_bps

Stripe’s currency-conversion fee, for the estimate. Defaults to the country’s.

integer
<= 10000
fee_schedule

The whole schedule, row by row: every card class online and card-present, once.

Array<object>
object
bps
required
integer
<= 10000
card_present
required

This row prices a terminal’s charge rather than an online one.

boolean
fee_class
required

The card’s class: regional is the EEA for a UK account and the UK for a eurozone one.

string
Allowed values: domestic_standard domestic_premium regional international
fixed
required

The fixed fee the hotel pays — Stripe’s own, passed through.

object
amount
required

Exact decimal as a string. Money is never a float — binary floating point cannot hold 0.10.

string format: decimal
currency
required
string format: iso-4217
processor_bps
required
integer
<= 10000
processor_fixed
required
object
amount
required

Exact decimal as a string. Money is never a float — binary floating point cannot hold 0.10.

string format: decimal
currency
required
string format: iso-4217
markup_bps

The platform’s markup over Stripe’s published rate for each card class, in basis points — the country’s table plus this. Defaults to 40 (Stripe + 0.40%). Not with fee_schedule.

integer

The account, opened and waiting on the hotel.

Media typeapplication/json
object
idempotent_replay
boolean
merchant_account_id
required
string format: uuid
status
required
string
Allowed values: onboarding
Example
{
"status": "onboarding"
}
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"
}
}

merchant_account_exists — the property already has an account that is not closed.

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

The country is not an ISO 3166-1 alpha-2 code, or the fee is outside 0–10000 basis points.

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 — the card processor could not be reached (a transport failure, a 5xx, a 429, or this request’s key still running at the processor). No account was opened. Try again after Retry-After.

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.