Skip to content

Record a late chargeback win settled by hand

POST
/v1/payment-disputes/{dispute_id}/late-win/settlement
curl --request POST \
--url https://api.aerandil.com/v1/payment-disputes/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/late-win/settlement \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "amount": { "amount": "example", "currency": "example" }, "note": "example", "outcome": "transferred_by_hand", "reference": "example" }'

When a chargeback lost and then won late leaves the case hotel_reinstatement = pending_operator — Stripe refused the card rail’s transfer back to the hotel (“If your platform has an insufficient balance, the transfer fails”; a cross-border corridor Stripe does not allow), or the dispute fee’s outcome was unknown — the rail never asks again and the money moves by hand. This records what the operator did: transferred_by_hand (they paid the hotel exactly what the case owed, reference naming the Stripe transfer tr_… or payout po_… they made, if any) or written_off (amount, from nothing up to what was owed, went back; the rest is not owed, for the reason in note). The case becomes settled_by_operator, keeps the processor’s refusal beside the settlement, and the card rail cannot write over it. Stripe is asked nothing. A case not left for the operator, an amount that is not what it owed, another currency, or a write-off without a note is a 422; the same settlement again changes nothing, a different one after it is a 422. Accepts Idempotency-Key. Operator only (tenant_admin:write).

dispute_id
required
string format: uuid

The chargeback case (payment_dispute).

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
amount
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
note

How it was settled; required for a write-off.

string
outcome
required
string
Allowed values: transferred_by_hand written_off
reference

The Stripe transfer (tr_…) or payout (po_…) that paid the hotel.

string

The case as settled.

Media typeapplication/json
object
amount
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
hotel_reinstatement
string
idempotent_replay
boolean
payment_dispute_id
string format: uuid
settled_at
string format: date-time
settled_by
string
settlement
string
version
integer
written_off
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
Examplegenerated
{
"amount": {
"amount": "example",
"currency": "example"
},
"hotel_reinstatement": "example",
"idempotent_replay": true,
"payment_dispute_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
"settled_at": "2026-04-15T12:00:00Z",
"settled_by": "example",
"settlement": "example",
"version": 1,
"written_off": {
"amount": "example",
"currency": "example"
}
}
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"
}
}

Another request with this Idempotency-Key is still running; retry shortly.

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

Not a case left for the operator, or not what it owed.

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