Skip to content

Rebook (move) a booking to a new departure, with its price revision

POST
/rebookings
curl --request POST \
--url https://quikstik-core.fly.dev/rebookings \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'x-tenant-id: 2489E9AD-2EE2-8E00-8EC9-32D5F69181C0' \
--data '{ "booking_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "obligation_ref": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "new_offering_variant_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "new_start_time": "2026-04-15T12:00:00Z", "new_capacity": 1, "revision": "even_exchange", "effective_date": { "year": 1, "month": 1, "day": 1 } }'

Moves one booking — addressed by booking_id + obligation_ref — to a new departure (new_offering_variant_id + new_start_time) and posts the price revision against the obligation. The durable effect is one transaction: the booking moves, its capacity is swapped (the old departure’s seat released, the new one held), and the money leg the revision directs is enqueued for the ledger to settle asynchronously: upcharge → priced-charge, downgrade → partial refund, even_exchange → no money event. Idempotent: a rebook that moves money requires an Idempotency-Key (400 without one). Fail-closed: 503 when no backend is wired.

x-tenant-id
required
string format: uuid

Tenant identifier (UUID).

Authn/authz semantics are intentionally TBD for this contract slice; this header exists to keep the contract explicitly multi-tenant from day 0.

Media typeapplication/json
object
booking_id
required

The booking being moved.

string format: uuid
obligation_ref
required

The booking’s ledger obligation (the revision posts against it).

string format: uuid
new_offering_variant_id
required

The offering variant of the new departure.

string format: uuid
new_start_time
required

Start time of the new departure (RFC3339 UTC); with the variant, the departure key.

string format: date-time
new_capacity

Recorded capacity of the new departure if it must be created (null = uncapped).

integer format: int32
nullable
revision
required
One of:

Same price — no money event, only the lifecycle move.

string
Allowed values: even_exchange
effective_date
required

Business/effective date of the rebook, for period close.

object
year
required
integer format: int32
month
required
integer
>= 1 <= 12
day
required
integer
>= 1 <= 31

Rebook accepted; capacity swapped and any money leg enqueued

Media typeapplication/json
object
booking_id
required
string format: uuid
obligation_ref
required
string format: uuid
status
required

The booking stays an active booking after the move.

string
Allowed values: rebooked
money
required

Which ledger leg the rebook drove (none for an even exchange).

string
Allowed values: priced_charge refund none

Example

{
"status": "rebooked",
"money": "priced_charge"
}

Malformed body, missing idempotency key, or a non-positive directed amount (an upcharge list or a downgrade net that is not strictly positive).

Media typeapplication/json
object
reason
required

Stable, machine-readable reason code (e.g. “sold_out”, “processor_not_configured”, “rail_refused”).

string

Example

{
"reason": "sold_out"
}

Missing or invalid session bearer token

Media typeapplication/json
object
reason
required

Stable, machine-readable reason code (e.g. “sold_out”, “processor_not_configured”, “rail_refused”).

string

Example

{
"reason": "sold_out"
}

The session’s effect authority does not cover this operation

Media typeapplication/json
object
reason
required

Stable, machine-readable reason code (e.g. “sold_out”, “processor_not_configured”, “rail_refused”).

string

Example

{
"reason": "sold_out"
}

No room on the target departure’s capacity chain — the leaf or an ancestor (e.g. the permit hour window) is short. Nothing changed: the booking stays on its old departure. pool_key names the short pool and short_by the seats missing, so the operator can raise the right dial and retry (never a 503: an outage would say so).

Media typeapplication/json
object
reason
required

capacity_full is the name. no_room is the old name, kept in this enum for one release for clients that matched on it; the gateway no longer sends it as reason and says deprecated_reason: no_room alongside instead.

string
Allowed values: capacity_full no_room
deprecated_reason

Present with capacity_full for one release — the old reason, so a client that matched on it still can.

string
Allowed values: no_room
pool_key
required
string
short_by
required
integer
>= 1

Example

{
"reason": "capacity_full",
"deprecated_reason": "no_room"
}

No durable backend is wired for this operation (fail-closed)

Media typeapplication/json
object
reason
required

Stable, machine-readable reason code (e.g. “sold_out”, “processor_not_configured”, “rail_refused”).

string

Example

{
"reason": "sold_out"
}