Skip to content

Set a scope's policy document (new version; the old one retires)

PUT
/policies/{scope_kind}/{scope_ref}
curl --request PUT \
--url https://quikstik-core.fly.dev/policies/tenant/example \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'x-tenant-id: 2489E9AD-2EE2-8E00-8EC9-32D5F69181C0' \
--data '{ "cancel": { "tiers": [ { "min_hours_before": 1, "refund_bps": 1 } ], "below": { "kind": "refund_all", "bps": 1, "fee": { "kind": "none", "minor": 1, "currency": "USD", "bps": 1 } } }, "reschedule": { "tiers": [ { "min_hours_before": 1, "outcome": { "kind": "refund_all", "bps": 1, "fee": { "kind": "none", "minor": 1, "currency": "USD", "bps": 1 } } } ], "below": { "kind": "refund_all", "bps": 1, "fee": { "kind": "none", "minor": 1, "currency": "USD", "bps": 1 } } }, "fee": { "kind": "none", "minor": 1, "currency": "USD", "bps": 1 }, "refund_as": { "kind": "money", "expires_days": 1 }, "weather": { "kind": "none", "decision_hour_local": 1, "forecast_source": "example", "rain_chance_bps": 1, "fraction_of_ride_bps": 1, "outcome": "full_refund_or_rebook" }, "no_show": { "kind": "refund_all", "bps": 1, "fee": { "kind": "none", "minor": 1, "currency": "USD", "bps": 1 } }, "overrides": { "waiver_reasons": [ "hardship" ] }, "text": { "summary_short": "example", "summary_multi_day": "example" }, "governs": true }'

Auth: a staff session, or an operator key scoped policies.write (underwritten only by an Admin/Owner membership; the audit actor is the key’s actor id) — a key without the scope is 403 insufficient_scope, an unknown or publishable key 401. scope_ref is - for tenant, an offering or variant uuid for offering/variant, and a channel key for channel. The body is a partial policy: every rule is optional and anything unset inherits. operator_cancel is fixed at refund_all and a document that tries to set it is refused. A channel document applies only when it says governs: true. Bookings made from now on snapshot the new terms; existing bookings keep theirs.

422 carries reasons — stable codes such as operator_cancel_not_configurable, bps_over_hundred_percent, outcome_not_executable, governs_only_on_channel, channel_document_must_govern, duplicate_waiver_reason, malformed_document (with detail) — and a bad scope is invalid_scope_kind / invalid_scope_ref. An audit event is written in the same transaction.

scope_kind
required
string
Allowed values: tenant offering variant channel
scope_ref
required
string
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

A scope’s partial policy: every rule optional, absent = inherit. operator_cancel is not settable (the server refuses a document that names it). governs is for channel scope only.

object
cancel

Tiers are most-notice-first; the most generous qualifying tier applies, else below.

object
tiers
required
Array<object>
object
min_hours_before
required
integer
refund_bps
required
integer
<= 10000
below
required

One rule’s verdict. For a cancel, refund_all/no_refund/refund are the refund fraction; for a reschedule refund_all means a free change and no_refund means not allowed. ota_governed is produced by resolution for a booking whose channel governs it and is never stored in a document. refund carries bps; fee carries fee.

object
kind
required
string
Allowed values: refund_all no_refund refund fee ota_governed
bps
integer
<= 10000
fee

none as the inner fee of a fee outcome means “use the policy’s own fee”. flat carries minor + currency; percent carries bps; keep_deposit carries nothing.

object
kind
required
string
Allowed values: none flat percent keep_deposit
minor
integer format: int64
currency
string
Allowed values: USD
bps
integer
<= 10000
reschedule
object
tiers
required
Array<object>
object
min_hours_before
required
integer
outcome
required

One rule’s verdict. For a cancel, refund_all/no_refund/refund are the refund fraction; for a reschedule refund_all means a free change and no_refund means not allowed. ota_governed is produced by resolution for a booking whose channel governs it and is never stored in a document. refund carries bps; fee carries fee.

object
kind
required
string
Allowed values: refund_all no_refund refund fee ota_governed
bps
integer
<= 10000
fee

none as the inner fee of a fee outcome means “use the policy’s own fee”. flat carries minor + currency; percent carries bps; keep_deposit carries nothing.

object
kind
required
string
Allowed values: none flat percent keep_deposit
minor
integer format: int64
currency
string
Allowed values: USD
bps
integer
<= 10000
below
required

One rule’s verdict. For a cancel, refund_all/no_refund/refund are the refund fraction; for a reschedule refund_all means a free change and no_refund means not allowed. ota_governed is produced by resolution for a booking whose channel governs it and is never stored in a document. refund carries bps; fee carries fee.

object
kind
required
string
Allowed values: refund_all no_refund refund fee ota_governed
bps
integer
<= 10000
fee

none as the inner fee of a fee outcome means “use the policy’s own fee”. flat carries minor + currency; percent carries bps; keep_deposit carries nothing.

object
kind
required
string
Allowed values: none flat percent keep_deposit
minor
integer format: int64
currency
string
Allowed values: USD
bps
integer
<= 10000
fee

none as the inner fee of a fee outcome means “use the policy’s own fee”. flat carries minor + currency; percent carries bps; keep_deposit carries nothing.

object
kind
required
string
Allowed values: none flat percent keep_deposit
minor
integer format: int64
currency
string
Allowed values: USD
bps
integer
<= 10000
refund_as
object
kind
required
string
Allowed values: money credit
expires_days
integer
weather
object
kind
required
string
Allowed values: none clause
decision_hour_local
integer
<= 23
forecast_source
string
rain_chance_bps
integer
<= 10000
fraction_of_ride_bps
integer
<= 10000
outcome
string
Allowed values: full_refund_or_rebook
no_show

One rule’s verdict. For a cancel, refund_all/no_refund/refund are the refund fraction; for a reschedule refund_all means a free change and no_refund means not allowed. ota_governed is produced by resolution for a booking whose channel governs it and is never stored in a document. refund carries bps; fee carries fee.

object
kind
required
string
Allowed values: refund_all no_refund refund fee ota_governed
bps
integer
<= 10000
fee

none as the inner fee of a fee outcome means “use the policy’s own fee”. flat carries minor + currency; percent carries bps; keep_deposit carries nothing.

object
kind
required
string
Allowed values: none flat percent keep_deposit
minor
integer format: int64
currency
string
Allowed values: USD
bps
integer
<= 10000
overrides
object
waiver_reasons
required
Array<string>
Allowed values: hardship rain_rule goodwill flight_disruption
text

Rendering hints only; the full page renders from the rules.

object
summary_short
required
string
summary_multi_day
string
governs
boolean

Stored as the scope’s next version

Media typeapplication/json
object
scope_kind
required
string
Allowed values: tenant offering variant channel
scope_ref
required
string
version
required
integer
>= 1

Example

{
"scope_kind": "tenant"
}

Invalid document or scope.

Media typeapplication/json
object
reason
required
string
reasons
Array<string>
detail
string

Example generated

{
"reason": "example",
"reasons": [
"example"
],
"detail": "example"
}

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