Skip to content

Cancel an open balance link

POST
/balance-links/{link_id}/cancellation
curl --request POST \
--url https://quikstik-core.fly.dev/balance-links/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/cancellation \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'x-idempotency-key: example' \
--data '{ "reason": "example" }'

Session bearer ONLY. Requires x-idempotency-key. One transaction: open → cancelled and the commerce.balance_link.cancelled outbox event carrying the reason. A repeat on an already-cancelled link is 200 with already_cancelled: true and writes no second event. A paid or expired link is 409 not_open (the body names which) and is untouched. No money moves and the guest is not emailed. Afterwards GET /b/{token} answers 410 link_cancelled.

link_id
required
string format: uuid
x-idempotency-key
required
string
Media typeapplication/json
object
reason
required
string
>= 1 characters <= 500 characters

Example generated

{
"reason": "example"
}

Cancelled now, or already cancelled (idempotent).

Media typeapplication/json
object
link_id
required
string format: uuid
status
required
string
Allowed values: cancelled
already_cancelled
required
boolean

Example

{
"status": "cancelled"
}

Idempotency_key_required.

Missing/invalid session, or an operator key (not accepted here).

No membership in the tenant.

Balance_link_not_found (unknown, or another tenant’s).

Not_open — the link is paid or expired.

Media typeapplication/json
object
reason
required
string
Allowed values: not_open
status
required
string
Allowed values: paid expired

Example

{
"reason": "not_open",
"status": "paid"
}

Invalid_link_id, reason_required, or reason_too_long.

Backend unavailable; the transaction rolled back, safe to retry.