The API the bakery's console calls, and a visitor's own client can too.
Every console action has a call here. Every bakery is a private sandbox of synthetic data, wiped at the next 10:00 UTC. From a browser, the __Host-session cookie carries the session; from anywhere else, the sandbox's API token goes in Authorization: Bearer (signed-in sandboxes only; issue it in the console or with POST /v1/sandboxes/{id}/token). A request with a token and no cookie needs no Origin. Every POST carries an Idempotency-Key, a ULID; the same key again gets the first answer with Idempotent-Replayed: true. Every error is application/problem+json (RFC 9457), its typehttps://bakery.ihaveasegway.com/problems/<slug>. Money is integer US cents; business times carry the bakery's Mountain offset, wall times are UTC with Z. Generated from crates/contracts: the route table and the schemas.
The document itself, OpenAPI 3.1, is at /docs/api/openapi.json. This page is built from it, and it is built from the same route table and schemas as the console’s types, so the three cannot disagree.
Servers
https://api.bakery.ihaveasegway.com: The API, from the launch (PR 11) on
http://127.0.0.1:8788: The API on wrangler dev, as workers/api/README.md runs it
Using your token
Sign in, open the console and press Issue token. The token is shown once. Send it as Authorization: Bearer <your token> on any route marked “token accepted”, with no cookie and no Origin. A token lasts 24 hours, dies with the sandbox and stops the moment you rotate it. A token in a query string, or a token beside a cookie, is refused with 400 token; a rotated or expired one is 401token. Every POST carries an Idempotency-Key, a ULID.
Today's admission state, the status page's counters and the breaker's state, from the Control object
Anyone.
Operation status · added in PR 2. Public: no session needed. No token: the cookie or nothing.
Answers
200StatusResponse: today's sandboxes, guests and demo accounts with their caps, the last snapshot of the kept Analytics Engine queries with counters_as_of and counters_state (live, stale or unavailable), the breaker's state (unconfigured, armed, read-only or off) with its last run, and the flag
Create a demo account behind Turnstile; the username is shown once
Anyone; a session, if present, is read but not required. Carries an Idempotency-Key.
Operation demo-signup · added in PR 3. Public: no session needed. No token: the cookie or nothing.
Parameters
Name
In
Required
Type
Meaning
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
400Problem (problems: idempotency-key, body): idempotency-key: no Idempotency-Key, or not a ULID; body: a body that is not the contract's JSON
403Problem (problems: turnstile, origin): turnstile: Turnstile refused the token; origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site
422Problem (problems: password, idempotency-key): password: 12 to 128 characters; idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, with Retry-After
503Problem (problem: demo-cap): demo-cap: the day's demo accounts are used up
curl -X POST 'https://api.bakery.ihaveasegway.com/v1/auth/demo' \
-H 'Idempotency-Key: <a new ULID>' \
-H 'Content-Type: application/json' \
-d '{"password":"<string>","turnstile_token":"<string>"}'
POST/v1/auth/demo/signin
Sign in to a demo account
Anyone; a session, if present, is read but not required. Carries an Idempotency-Key.
Operation demo-signin · added in PR 3. Public: no session needed. No token: the cookie or nothing.
Parameters
Name
In
Required
Type
Meaning
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
400Problem (problems: idempotency-key, body): idempotency-key: no Idempotency-Key, or not a ULID; body: a body that is not the contract's JSON
401Problem (problem: credentials): credentials: no such username, or the wrong password
403Problem (problem: origin): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site
422Problem (problem: idempotency-key): idempotency-key: the same key again with a different body
429Problem (problems: locked, rate-limit): locked: 10 failures in 15 minutes; with Retry-After; rate-limit: the session's or IP hash's limit, with Retry-After
Sign out: the cookie is cleared and an account's session id revoked
Any session, a guest's included. Carries an Idempotency-Key.
Operation signout · added in PR 3. Any session, a guest’s included. No token: the cookie or nothing.
Parameters
Name
In
Required
Type
Meaning
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
Answers
204: the cookie cleared
400Problem (problems: idempotency-key, token): idempotency-key: no Idempotency-Key, or not a ULID; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: an API token: this route takes the session cookie only (cookie-only); session: no session, or one that does not verify
403Problem (problem: origin): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site
422Problem (problem: idempotency-key): idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, with Retry-After
This route takes the console’s cookie only, so a token cannot call it: a token never mints its successor, and a browser session is the only way to sign in.
GET/v1/session
What the cookie says, read without an object call
Any session, a guest's included.
Operation session · added in PR 3. Any session, a guest’s included. No token: the cookie or nothing.
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: an API token: this route takes the session cookie only (cookie-only); session: no session, or one that does not verify
This route takes the console’s cookie only, so a token cannot call it: a token never mints its successor, and a browser session is the only way to sign in.
Sandbox
POST/v1/sandboxes
A sandbox: Turnstile for a guest, admitted by Control, seeded
Anyone; a session, if present, is read but not required. Carries an Idempotency-Key.
Operation create-sandbox · added in PR 3. Public: no session needed. No token: the cookie or nothing.
Parameters
Name
In
Required
Type
Meaning
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
200SandboxResponse: an account's live sandbox, unless replace
201SandboxResponse: a new sandbox; the cookie is re-issued with sbx
400Problem (problems: idempotency-key, body): idempotency-key: no Idempotency-Key, or not a ULID; body: a body that is not the contract's JSON
403Problem (problems: turnstile, origin): turnstile: a guest without a good Turnstile token; origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site
422Problem (problem: idempotency-key): idempotency-key: the same key again with a different body
429Problem (problems: rate-limit, account-sandbox-cap): rate-limit: this IP hash's creations this minute; account-sandbox-cap: 3 sandboxes an account a day
503Problem (problems: sandbox-cap, guest-cap, read-only, off): sandbox-cap: 300 sandboxes a UTC day; guest-cap: 100 guest sandboxes a UTC day; read-only: the demo's flag is read-only; off: the demo's flag is off
curl -X POST 'https://api.bakery.ihaveasegway.com/v1/sandboxes' \
-H 'Idempotency-Key: <a new ULID>' \
-H 'Content-Type: application/json' \
-d '{}'
DELETE/v1/sandboxes/{id}
Wipe now, finished in the request
A session of sandbox {id}, a guest's included. The sandbox's API token may stand in for the cookie.
Operation wipe-sandbox · added in PR 3. A session of this sandbox, a guest’s included. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
Answers
200WipedResponse: {id, state: wiped}; an account's cookie loses sbx, a guest's is cleared
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problem: origin): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site
404Problem: another sandbox's id, or one naming nothing
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
404Problem: another sandbox's id, or one naming nothing
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
429Problem (problem: rate-limit): rate-limit: with a token, the token's limit: every request it makes counts, with Retry-After
Move business time forward, at most 14 days in all
A signed-in session of sandbox {id}; a guest gets 403 guest-scope. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation advance-clock · added in PR 4. A signed-in session of this sandbox; a guest gets 403 guest-scope. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
200ClockResponse: the clock, with step; the same key again: the first answer, and nothing moves again
400Problem (problems: idempotency-key, body, token): idempotency-key: no Idempotency-Key, or not a ULID; body: a body that is not the contract's JSON; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problems: origin, guest-scope): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site; guest-scope: a guest's session: sign in for this
404Problem: another sandbox's id, or one naming nothing
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problems: clock, idempotency-key): clock: naming offset-cap or not-positive (also for both or neither); idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
A session of sandbox {id}, a guest's included. The sandbox's API token may stand in for the cookie.
Operation list-dead-letters · added in PR 4. A session of this sandbox, a guest’s included. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
Answers
200: an array of dead letters
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
404Problem: another sandbox's id, or one naming nothing
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
429Problem (problem: rate-limit): rate-limit: with a token, the token's limit: every request it makes counts, with Retry-After
A signed-in session of sandbox {id}; a guest gets 403 guest-scope. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation redrive · added in PR 4. A signed-in session of this sandbox; a guest gets 403 guest-scope. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
eventId
path
yes
string
The dead-lettered event's ULID.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
Answers
200DeadLetter: the dead letter sent again, its row removed
400Problem (problems: idempotency-key, token): idempotency-key: no Idempotency-Key, or not a ULID; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problems: origin, guest-scope): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site; guest-scope: a guest's session: sign in for this
404Problem: an id this sandbox has not registered, another's included
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problem: idempotency-key): idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
The last delivery error, as a reason code such as Kitchen answered 503.
id
string
yes
The event's ULID: the key a redrive sends it again with.
seq
integer
yes
at least 0
stream
string
yes
The producing object's name.
type
string
yes
The event type, such as OrderPlaced.
curl
curl -X POST 'https://api.bakery.ihaveasegway.com/v1/sandboxes/<sandbox id>/dead-letters/<eventId>/redrive' \
-H 'Authorization: Bearer <your token>' \
-H 'Idempotency-Key: <a new ULID>'
POST/v1/sandboxes/{id}/faults
Switch the Kitchen's or the Inbox's broken-subscriber fault
A signed-in session of sandbox {id}; a guest gets 403 guest-scope. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation set-fault · added in PR 3. A signed-in session of this sandbox; a guest gets 403 guest-scope. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
400Problem (problems: idempotency-key, body, token): idempotency-key: no Idempotency-Key, or not a ULID; body: a body that is not the contract's JSON; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problems: origin, guest-scope): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site; guest-scope: a guest's session: sign in for this
404Problem: another sandbox's id, or one naming nothing
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problem: idempotency-key): idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
404Problem: another sandbox's id, or one naming nothing
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
429Problem (problem: rate-limit): rate-limit: with a token, the token's limit: every request it makes counts, with Retry-After
503Problem (problem: seeding): seeding: the sandbox is still being seeded
400Problem (problems: body, token): body: a body that is not the contract's JSON; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problems: origin, guest-scope): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site; guest-scope: a guest's session: sign in for this
Publish the drafts: `MenuPublished`, the version plus one
A signed-in session of sandbox {id}; a guest gets 403 guest-scope. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation publish-menu · added in PR 4. A signed-in session of this sandbox; a guest gets 403 guest-scope. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
400Problem (problems: idempotency-key, token): idempotency-key: no Idempotency-Key, or not a ULID; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problems: origin, guest-scope): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site; guest-scope: a guest's session: sign in for this
404Problem: another sandbox's id, or one naming nothing
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problems: menu, idempotency-key): menu: no drafts to publish; idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
curl -X POST 'https://api.bakery.ihaveasegway.com/v1/sandboxes/<sandbox id>/menu/publish' \
-H 'Authorization: Bearer <your token>' \
-H 'Idempotency-Key: <a new ULID>'
Orders
POST/v1/sandboxes/{id}/orders
Place an order as the sandbox's persona; its slot is held until it is paid
A session of sandbox {id}, a guest's included. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation place-order · added in PR 4. A session of this sandbox, a guest’s included. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
400Problem (problems: idempotency-key, body, token): idempotency-key: no Idempotency-Key, or not a ULID; body: a body that is not the contract's JSON; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problem: origin): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site
404Problem: another sandbox's id, or one naming nothing
409Problem (problems: slot-full, item-cap, lead-time, hold-lost): slot-full: with next_free, the next free start that day; item-cap: an item's daily cap is reached; lead-time: naming the hours, such as a 48 h cake for tomorrow; hold-lost: a retry whose place was given back before any order was placed, with no room left; with next_free
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problems: no-such-slot, closed-day, order, idempotency-key): no-such-slot: not a slot or window start, or a day outside the sandbox's; closed-day: the bakery is closed that day; order: naming the rule (note-<class> for the note); idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
503Problem (problem: seeding): seeding: the sandbox is still being seeded
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
404Problem: an id this sandbox has not registered, another's included
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
429Problem (problem: rate-limit): rate-limit: with a token, the token's limit: every request it makes counts, with Retry-After
A session of sandbox {id}, a guest's included. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation cancel-order · added in PR 4. A session of this sandbox, a guest’s included. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
oid
path
yes
string
An order's ULID.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
400Problem (problems: idempotency-key, token): idempotency-key: no Idempotency-Key, or not a ULID; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problem: origin): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site
404Problem: an id this sandbox has not registered, another's included
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problems: order, idempotency-key): order: naming the rule; idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
one of placed, confirmed, expired, cancelled, refund_pending, in_production, ready, picked_up, out_for_delivery, delivered, closed
subtotal_cents
integer
yes
tax_cents
integer
yes
total_cents
integer
yes
zone
string or null
no
curl
curl -X POST 'https://api.bakery.ihaveasegway.com/v1/sandboxes/<sandbox id>/orders/<oid>/cancel' \
-H 'Authorization: Bearer <your token>' \
-H 'Idempotency-Key: <a new ULID>'
POST/v1/sandboxes/{id}/orders/{oid}/payment
What the browser needs to mount Stripe's Payment Element; only the webhook marks it paid
A session of sandbox {id}, a guest's included. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation pay · added in PR 5. A session of this sandbox, a guest’s included. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
oid
path
yes
string
An order's ULID.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
Answers
200PaymentResponse: the payment and its one-time client_secret
400Problem (problems: idempotency-key, token): idempotency-key: no Idempotency-Key, or not a ULID; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problem: origin): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site
curl -X POST 'https://api.bakery.ihaveasegway.com/v1/sandboxes/<sandbox id>/orders/<oid>/payment' \
-H 'Authorization: Bearer <your token>' \
-H 'Idempotency-Key: <a new ULID>'
POST/v1/sandboxes/{id}/orders/{oid}/refund
Staff refund a part or all that is left; Billing refunds at Stripe from the Queue
A signed-in session of sandbox {id}; a guest gets 403 guest-scope. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation refund · added in PR 5. A signed-in session of this sandbox; a guest gets 403 guest-scope. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
oid
path
yes
string
An order's ULID.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
200RefundResponse: the refund, on its way to Stripe; the same Idempotency-Key again: the first answer, replayed
400Problem (problems: idempotency-key, body, token): idempotency-key: no Idempotency-Key, or not a ULID; body: a body that is not the contract's JSON; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problems: origin, guest-scope): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site; guest-scope: a guest's session: sign in for this
404Problem: another sandbox's id, or one naming nothing
409Problem (problem: order): order: no-stripe-payment: a seeded order Stripe never charged
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problems: order, idempotency-key): order: refund-exceeds-paid or out-of-order; idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
503Problem (problem: stripe-key): stripe-key: the API has no sandbox Stripe key
The console is open with no socket: the Kitchen keeps the time for the Simulator
A session of sandbox {id}, a guest's included. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation heartbeat · added in PR 4. A session of this sandbox, a guest’s included. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
Answers
204: noted
400Problem (problems: idempotency-key, token): idempotency-key: no Idempotency-Key, or not a ULID; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problem: origin): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problem: idempotency-key): idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
curl
curl -X POST 'https://api.bakery.ihaveasegway.com/v1/sandboxes/<sandbox id>/heartbeat' \
-H 'Authorization: Bearer <your token>' \
-H 'Idempotency-Key: <a new ULID>'
GET/v1/sandboxes/{id}/kitchen/ws
The kitchen board's socket, protocol v1 (`x-websocket`)
A session of sandbox {id}, by the cookie only, with the storefront's exact Origin.
Operation kitchen-socket · added in PR 4. The session cookie only. No token: the cookie or nothing.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
Answers
101: the socket; frames in x-websocket
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: an API token: this route takes the session cookie only (cookie-only); session: no session, or one that does not verify
403Problem (problem: origin): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problems: origin, guest-scope): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site; guest-scope: a guest's session: sign in for this
404Problem: another sandbox's id, or one naming nothing
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
404Problem: another sandbox's id, or one naming nothing
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
429Problem (problem: rate-limit): rate-limit: with a token, the token's limit: every request it makes counts, with Retry-After
Start simulated orders, 1 to 6 a minute, within today's 30 minutes
A signed-in session of sandbox {id}; a guest gets 403 guest-scope. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation start-traffic · added in PR 4. A signed-in session of this sandbox; a guest gets 403 guest-scope. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
200TrafficResponse: the Simulator, running; the same Idempotency-Key again: the first answer, replayed
400Problem (problems: idempotency-key, body, token): idempotency-key: no Idempotency-Key, or not a ULID; body: a body that is not the contract's JSON; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problems: origin, guest-scope): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site; guest-scope: a guest's session: sign in for this
404Problem: another sandbox's id, or one naming nothing
409Problem (problem: traffic-running): traffic-running: a run is already going
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problems: traffic, idempotency-key): traffic: naming the rule; idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
503Problem (problem: traffic-cap): traffic-cap: today's minutes are used; with Retry-After
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
404Problem: another sandbox's id, or one naming nothing
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
429Problem (problem: rate-limit): rate-limit: with a token, the token's limit: every request it makes counts, with Retry-After
503Problem (problem: stripe-key): stripe-key: the API has no sandbox Stripe key
Stripe's events, checked against `Stripe-Signature`, test mode only; no CORS, Origin, session, key or rate limit
Stripe only: its signature is the check.
Operation stripe-webhook · added in PR 5. Stripe only, by its signature. No token: the cookie or nothing.
Answers
200: an event applied, replayed or ignored, and for a wiped or unknown sandbox
400Problem (problems: signature, timestamp, body, livemode): signature: the signature does not verify; timestamp: the signature's timestamp is outside the tolerance; body: not a Stripe event; livemode: a live-mode event
405Problem: OPTIONS, with Allow: POST: no preflight
409Problem (problem: webhook-later): webhook-later: an event Billing cannot apply yet
503Problem (problem: stripe-key): stripe-key: the API has no sandbox Stripe key
This route takes the console’s cookie only, so a token cannot call it: a token never mints its successor, and a browser session is the only way to sign in.
Schedule
GET/v1/sandboxes/{id}/schedule/{date}
One bakery day: slots, zones, item caps, catering and the bake list
A session of sandbox {id}, a guest's included. The sandbox's API token may stand in for the cookie.
Operation get-schedule · added in PR 6. A session of this sandbox, a guest’s included. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
404Problem (problem: no-such-day): no-such-day: a date outside the sandbox's days
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
429Problem (problem: rate-limit): rate-limit: with a token, the token's limit: every request it makes counts, with Retry-After
503Problem (problem: seeding): seeding: the sandbox is still being seeded
The new capacity. Places already taken stay; a cut below them only stops new ones.
target
string
yes
What to change, in the domain's grammar: slot:HH:MM (a slot start on the quarter hour, such as slot:14:45), zone:z1 (to z3), item:<slug> (such as item:croissant) or catering.
400Problem (problems: body, token): body: a body that is not the contract's JSON; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problems: origin, guest-scope): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site; guest-scope: a guest's session: sign in for this
404Problem (problem: no-such-day): no-such-day: a date outside the sandbox's days
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problems: bad-target, unknown-item): bad-target: not slot:HH:MM, zone:z1 to z3, item:<slug> or catering; unknown-item: an item:<slug> the day's published menu does not list
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
404Problem: another sandbox's id, or one naming nothing
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
429Problem (problem: rate-limit): rate-limit: with a token, the token's limit: every request it makes counts, with Retry-After
A session of sandbox {id}, a guest's included. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation create-catering · added in PR 7. A session of this sandbox, a guest’s included. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
400Problem (problems: idempotency-key, body, token): idempotency-key: no Idempotency-Key, or not a ULID; body: a body that is not the contract's JSON; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problem: origin): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site
404Problem: another sandbox's id, or one naming nothing
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problems: catering, idempotency-key): catering: detail ends The rule is <slug>.; never echoes the brief; idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
404Problem: an id this sandbox has not registered, another's included
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
429Problem (problem: rate-limit): rate-limit: with a token, the token's limit: every request it makes counts, with Retry-After
Accept the quote: the day's catering place is held while the deposit is paid
A session of sandbox {id}, a guest's included. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation accept-quote · added in PR 7. A session of this sandbox, a guest’s included. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
cid
path
yes
string
A catering event's, a customer's or a campaign's ULID, as the path says.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
400Problem (problems: idempotency-key, token): idempotency-key: no Idempotency-Key, or not a ULID; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problem: origin): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site
404Problem: another sandbox's id, or one naming nothing
409Problem (problems: slot-full, catering): slot-full: both of the day's catering places are taken; nothing recorded; catering: out-of-order or quote-expired
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problem: idempotency-key): idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
When the quote stops being accepted, a business time: 07:00 on the 14th business day after the quote.
venue
string
yes
curl
curl -X POST 'https://api.bakery.ihaveasegway.com/v1/sandboxes/<sandbox id>/catering/<cid>/accept' \
-H 'Authorization: Bearer <your token>' \
-H 'Idempotency-Key: <a new ULID>'
POST/v1/sandboxes/{id}/catering/{cid}/cancel
The customer cancels a confirmed event; more than 7 days out the deposit is refunded
A session of sandbox {id}, a guest's included. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation cancel-catering · added in PR 7. A session of this sandbox, a guest’s included. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
cid
path
yes
string
A catering event's, a customer's or a campaign's ULID, as the path says.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
400Problem (problems: idempotency-key, body, token): idempotency-key: no Idempotency-Key, or not a ULID; body: a body that is not the contract's JSON; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problem: origin): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site
404Problem: another sandbox's id, or one naming nothing
A signed-in session of sandbox {id}; a guest gets 403 guest-scope. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation decline-catering · added in PR 7. A signed-in session of this sandbox; a guest gets 403 guest-scope. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
cid
path
yes
string
A catering event's, a customer's or a campaign's ULID, as the path says.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
400Problem (problems: idempotency-key, body, token): idempotency-key: no Idempotency-Key, or not a ULID; body: a body that is not the contract's JSON; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problems: origin, guest-scope): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site; guest-scope: a guest's session: sign in for this
404Problem: another sandbox's id, or one naming nothing
409Problem (problem: catering): catering: past inquiry
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problem: idempotency-key): idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
Staff mark it delivered; Billing raises the balance invoice
A signed-in session of sandbox {id}; a guest gets 403 guest-scope. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation mark-catering-delivered · added in PR 7. A signed-in session of this sandbox; a guest gets 403 guest-scope. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
cid
path
yes
string
A catering event's, a customer's or a campaign's ULID, as the path says.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
400Problem (problems: idempotency-key, token): idempotency-key: no Idempotency-Key, or not a ULID; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problems: origin, guest-scope): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site; guest-scope: a guest's session: sign in for this
404Problem: another sandbox's id, or one naming nothing
409Problem (problem: catering): catering: out-of-order; too-early before the event day
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problem: idempotency-key): idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
When the quote stops being accepted, a business time: 07:00 on the 14th business day after the quote.
venue
string
yes
curl
curl -X POST 'https://api.bakery.ihaveasegway.com/v1/sandboxes/<sandbox id>/catering/<cid>/delivered' \
-H 'Authorization: Bearer <your token>' \
-H 'Idempotency-Key: <a new ULID>'
POST/v1/sandboxes/{id}/catering/{cid}/deposit
The deposit's payment, 25% of the quote, as an order's `/payment`
A session of sandbox {id}, a guest's included. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation catering-deposit · added in PR 7. A session of this sandbox, a guest’s included. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
cid
path
yes
string
A catering event's, a customer's or a campaign's ULID, as the path says.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
Answers
200PaymentResponse: the payment and its one-time client_secret
400Problem (problems: idempotency-key, token): idempotency-key: no Idempotency-Key, or not a ULID; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problem: origin): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site
404Problem: another sandbox's id, or one naming nothing
curl -X POST 'https://api.bakery.ihaveasegway.com/v1/sandboxes/<sandbox id>/catering/<cid>/deposit' \
-H 'Authorization: Bearer <your token>' \
-H 'Idempotency-Key: <a new ULID>'
POST/v1/sandboxes/{id}/catering/{cid}/pay-balance
Pay the balance invoice on Stripe's test path; the webhook closes the event
A session of sandbox {id}, a guest's included. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation pay-balance · added in PR 7. A session of this sandbox, a guest’s included. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
cid
path
yes
string
A catering event's, a customer's or a campaign's ULID, as the path says.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
400Problem (problems: idempotency-key, token): idempotency-key: no Idempotency-Key, or not a ULID; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problem: origin): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site
404Problem: another sandbox's id, or one naming nothing
When the quote stops being accepted, a business time: 07:00 on the 14th business day after the quote.
venue
string
yes
curl
curl -X POST 'https://api.bakery.ihaveasegway.com/v1/sandboxes/<sandbox id>/catering/<cid>/pay-balance' \
-H 'Authorization: Bearer <your token>' \
-H 'Idempotency-Key: <a new ULID>'
POST/v1/sandboxes/{id}/catering/{cid}/quote
Staff quote an inquiry
A signed-in session of sandbox {id}; a guest gets 403 guest-scope. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation send-quote · added in PR 7. A signed-in session of this sandbox; a guest gets 403 guest-scope. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
cid
path
yes
string
A catering event's, a customer's or a campaign's ULID, as the path says.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
A staff override of the total, in cents, at least 1. Absent: the package's price per head times the headcount. The deposit is 25% of the total, rounded half-up.
400Problem (problems: idempotency-key, body, token): idempotency-key: no Idempotency-Key, or not a ULID; body: a body that is not the contract's JSON; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problems: origin, guest-scope): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site; guest-scope: a guest's session: sign in for this
404Problem: another sandbox's id, or one naming nothing
409Problem (problem: catering): catering: out-of-order, or quote-expired once the day before the event has begun
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problems: catering, idempotency-key): catering: quote-total, a total under 1 cent; idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
A signed-in session of sandbox {id}; a guest gets 403 guest-scope. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation staff-cancel-catering · added in PR 7. A signed-in session of this sandbox; a guest gets 403 guest-scope. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
cid
path
yes
string
A catering event's, a customer's or a campaign's ULID, as the path says.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
400Problem (problems: idempotency-key, body, token): idempotency-key: no Idempotency-Key, or not a ULID; body: a body that is not the contract's JSON; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problems: origin, guest-scope): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site; guest-scope: a guest's session: sign in for this
404Problem: another sandbox's id, or one naming nothing
409Problem (problem: catering): catering: out of order
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problem: idempotency-key): idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
A signed-in session of sandbox {id}; a guest gets 403 guest-scope. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation start-catering-production · added in PR 7. A signed-in session of this sandbox; a guest gets 403 guest-scope. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
cid
path
yes
string
A catering event's, a customer's or a campaign's ULID, as the path says.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
400Problem (problems: idempotency-key, token): idempotency-key: no Idempotency-Key, or not a ULID; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problems: origin, guest-scope): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site; guest-scope: a guest's session: sign in for this
404Problem: another sandbox's id, or one naming nothing
409Problem (problem: catering): catering: out-of-order unless confirmed; too-early before the day before the event
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problem: idempotency-key): idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
404Problem: another sandbox's id, or one naming nothing
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
429Problem (problem: rate-limit): rate-limit: with a token, the token's limit: every request it makes counts, with Retry-After
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
404Problem: another sandbox's id, or one naming nothing
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
429Problem (problem: rate-limit): rate-limit: with a token, the token's limit: every request it makes counts, with Retry-After
A signed-in session of sandbox {id}; a guest gets 403 guest-scope. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation create-campaign · added in PR 8. A signed-in session of this sandbox; a guest gets 403 guest-scope. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
400Problem (problems: idempotency-key, body, token): idempotency-key: no Idempotency-Key, or not a ULID; body: a body that is not the contract's JSON; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problems: origin, guest-scope): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site; guest-scope: a guest's session: sign in for this
404Problem: another sandbox's id, or one naming nothing
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problem: idempotency-key): idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
one of weekend-bake, cake-week, new-season, we-miss-you, catering-season, thank-you
Answers
200CampaignResponse: the draft; the same optional Idempotency-Key again replays it
400Problem (problems: body, token): body: a body that is not the contract's JSON; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problems: origin, guest-scope): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site; guest-scope: a guest's session: sign in for this
A scheduled campaign back to draft, or a draft cancelled
A signed-in session of sandbox {id}; a guest gets 403 guest-scope. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation cancel-campaign · added in PR 8. A signed-in session of this sandbox; a guest gets 403 guest-scope. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
cid
path
yes
string
A catering event's, a customer's or a campaign's ULID, as the path says.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
400Problem (problems: idempotency-key, token): idempotency-key: no Idempotency-Key, or not a ULID; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problems: origin, guest-scope): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site; guest-scope: a guest's session: sign in for this
one of weekend-bake, cake-week, new-season, we-miss-you, catering-season, thank-you
curl
curl -X POST 'https://api.bakery.ihaveasegway.com/v1/sandboxes/<sandbox id>/campaigns/<cid>/cancel' \
-H 'Authorization: Bearer <your token>' \
-H 'Idempotency-Key: <a new ULID>'
POST/v1/sandboxes/{id}/campaigns/{cid}/schedule
Schedule a draft; the send is the object's timer, never a route
A signed-in session of sandbox {id}; a guest gets 403 guest-scope. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation schedule-campaign · added in PR 8. A signed-in session of this sandbox; a guest gets 403 guest-scope. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
cid
path
yes
string
A catering event's, a customer's or a campaign's ULID, as the path says.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
400Problem (problems: idempotency-key, body, token): idempotency-key: no Idempotency-Key, or not a ULID; body: a body that is not the contract's JSON; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problems: origin, guest-scope): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site; guest-scope: a guest's session: sign in for this
409Problem (problem: campaign): campaign: out-of-order: not a draft
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problems: campaign, idempotency-key): campaign: schedule-too-soon, its detail the earliest time allowed; idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
404Problem: another sandbox's id, or one naming nothing
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
429Problem (problem: rate-limit): rate-limit: with a token, the token's limit: every request it makes counts, with Retry-After
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
Marketing consent, by the customer's own persona or by staff
A session of sandbox {id}, a guest's included. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation set-consent · added in PR 8. A session of this sandbox, a guest’s included. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
cid
path
yes
string
A catering event's, a customer's or a campaign's ULID, as the path says.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
200CustomerResponse: the customer; the same Idempotency-Key again replays it, with Idempotent-Replayed
400Problem (problems: idempotency-key, body, token): idempotency-key: no Idempotency-Key, or not a ULID; body: a body that is not the contract's JSON; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problems: guest-scope, origin): guest-scope: a guest changing another persona's consent; origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
A session of sandbox {id}, a guest's included. The sandbox's API token may stand in for the cookie.
Operation list-inbox · added in PR 8. A session of this sandbox, a guest’s included. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
kind
query
no
string
one message kind, such as receipt
to
query
no
string
one customer's ULID
limit
query
no
integer
how many, 50 when left out
Answers
200InboxResponse: the messages and the filters' total
400Problem (problems: filter, token): filter: a filter the inbox refuses; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
404Problem: another sandbox's id, or one naming nothing
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
429Problem (problem: rate-limit): rate-limit: with a token, the token's limit: every request it makes counts, with Retry-After
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
404Problem: another sandbox's id, or one naming nothing
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
429Problem (problem: rate-limit): rate-limit: with a token, the token's limit: every request it makes counts, with Retry-After
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
404Problem: another sandbox's id, or one naming nothing
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
429Problem (problem: rate-limit): rate-limit: with a token, the token's limit: every request it makes counts, with Retry-After
Rebuild projections: drop Crm's projections and replay its log
A signed-in session of sandbox {id}; a guest gets 403 guest-scope. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation start-rebuild · added in PR 8. A signed-in session of this sandbox; a guest gets 403 guest-scope. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
400Problem (problems: idempotency-key, token): idempotency-key: no Idempotency-Key, or not a ULID; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problems: origin, guest-scope): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site; guest-scope: a guest's session: sign in for this
404Problem: another sandbox's id, or one naming nothing
409Problem (problem: rebuild): rebuild: a second start while one is running; other commands still run
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problem: idempotency-key): idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
404Problem: another sandbox's id, or one naming nothing
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
429Problem (problem: rate-limit): rate-limit: with a token, the token's limit: every request it makes counts, with Retry-After
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
404Problem (problem: no-such-day): no-such-day: a date outside the sandbox's days
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
429Problem (problem: rate-limit): rate-limit: with a token, the token's limit: every request it makes counts, with Retry-After
503Problem (problem: seeding): seeding: the sandbox is still being seeded
Both plans' totals, when there are both; null while the browser's solver has not run or cannot (the page then shows the server's plan alone and says why).
date
string
yes
The bakery day, YYYY-MM-DD.
plan_v
integer
yes
0 to 65535
The published plan's version, 0 before the first publish.
A signed-in session of sandbox {id}; a guest gets 403 guest-scope. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation complete-stop · added in PR 9. A signed-in session of this sandbox; a guest gets 403 guest-scope. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
date
path
yes
string
A bakery day, YYYY-MM-DD.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
200DispatchResponse: the day; again for a delivered stop changes nothing
400Problem (problems: idempotency-key, body, token): idempotency-key: no Idempotency-Key, or not a ULID; body: a body that is not the contract's JSON; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problems: origin, guest-scope): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site; guest-scope: a guest's session: sign in for this
404Problem (problem: no-such-day): no-such-day: a date outside the sandbox's days
409Problem (problem: dispatch): dispatch: no-plan, or not-ready (the stop's order is not ready yet)
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problems: dispatch, idempotency-key): dispatch: stop-unknown; idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
503Problem (problem: seeding): seeding: the sandbox is still being seeded
Both plans' totals, when there are both; null while the browser's solver has not run or cannot (the page then shows the server's plan alone and says why).
date
string
yes
The bakery day, YYYY-MM-DD.
plan_v
integer
yes
0 to 65535
The published plan's version, 0 before the first publish.
The plan VROOM made in the browser; the server computes its minutes
A signed-in session of sandbox {id}; a guest gets 403 guest-scope. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation submit-plan · added in PR 9. A signed-in session of this sandbox; a guest gets 403 guest-scope. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
date
path
yes
string
A bakery day, YYYY-MM-DD.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
400Problem (problems: idempotency-key, body, token): idempotency-key: no Idempotency-Key, or not a ULID; body: a body that is not the contract's JSON; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problems: origin, guest-scope): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site; guest-scope: a guest's session: sign in for this
404Problem (problem: no-such-day): no-such-day: a date outside the sandbox's days
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problems: dispatch, idempotency-key): dispatch: route-ends, vans, stop-unknown, stop-twice, over-capacity, stop-missing, window (a stop reached after its delivery window closes) or no-stops; idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
503Problem (problem: seeding): seeding: the sandbox is still being seeded
Both plans' totals, when there are both; null while the browser's solver has not run or cannot (the page then shows the server's plan alone and says why).
date
string
yes
The bakery day, YYYY-MM-DD.
plan_v
integer
yes
0 to 65535
The published plan's version, 0 before the first publish.
A signed-in session of sandbox {id}; a guest gets 403 guest-scope. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation propose-dispatch · added in PR 9. A signed-in session of this sandbox; a guest gets 403 guest-scope. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
date
path
yes
string
A bakery day, YYYY-MM-DD.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
400Problem (problems: idempotency-key, body, token): idempotency-key: no Idempotency-Key, or not a ULID; body: a body that is not the contract's JSON; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problems: origin, guest-scope): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site; guest-scope: a guest's session: sign in for this
404Problem (problem: no-such-day): no-such-day: a date outside the sandbox's days
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problems: dispatch, idempotency-key): dispatch: vans, capacity, no-stops or place-unknown; idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
503Problem (problem: seeding): seeding: the sandbox is still being seeded
Both plans' totals, when there are both; null while the browser's solver has not run or cannot (the page then shows the server's plan alone and says why).
date
string
yes
The bakery day, YYYY-MM-DD.
plan_v
integer
yes
0 to 65535
The published plan's version, 0 before the first publish.
A signed-in session of sandbox {id}; a guest gets 403 guest-scope. The sandbox's API token may stand in for the cookie. Carries an Idempotency-Key.
Operation publish-dispatch · added in PR 9. A signed-in session of this sandbox; a guest gets 403 guest-scope. A token is accepted.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
date
path
yes
string
A bakery day, YYYY-MM-DD.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
200DispatchResponse: the day, with published; the same Idempotency-Key again: the first answer, replayed
400Problem (problems: idempotency-key, body, token): idempotency-key: no Idempotency-Key, or not a ULID; body: a body that is not the contract's JSON; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problems: origin, guest-scope): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site; guest-scope: a guest's session: sign in for this
404Problem (problem: no-such-day): no-such-day: a date outside the sandbox's days
409Problem (problem: dispatch): dispatch: no-plan, stop-missing, published (a van has left) or the plan's own rules again
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problem: idempotency-key): idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, or with a token the token's, with Retry-After
503Problem (problem: seeding): seeding: the sandbox is still being seeded
Both plans' totals, when there are both; null while the browser's solver has not run or cannot (the page then shows the server's plan alone and says why).
date
string
yes
The bakery day, YYYY-MM-DD.
plan_v
integer
yes
0 to 65535
The published plan's version, 0 before the first publish.
400Problem (problem: token): token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: a token that is malformed, expired, rotated or not an API token (token, expired, rotated, purpose); session: no session, or one that does not verify
403Problem (problem: guest-scope): guest-scope: a guest's session: sign in for this
404Problem: another sandbox's id, or one naming nothing
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
429Problem (problem: rate-limit): rate-limit: with a token, the token's limit: every request it makes counts, with Retry-After
Issue the sandbox's API token at its current version, or issue it again; shown once
A signed-in session of sandbox {id}; a guest gets 403 guest-scope. The cookie only: an API token never mints its successor. Carries an Idempotency-Key.
Operation issue-token · added in PR 10. A signed-in session of this sandbox; a guest gets 403 guest-scope. No token: the cookie or nothing.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
Answers
200TokenResponse: the token, shown once; the same Idempotency-Key again: the first answer, replayed
400Problem (problems: idempotency-key, token): idempotency-key: no Idempotency-Key, or not a ULID; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: an API token: this route takes the session cookie only (cookie-only); session: no session, or one that does not verify
403Problem (problems: origin, guest-scope): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site; guest-scope: a guest's session: sign in for this
404Problem: another sandbox's id, or one naming nothing
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problem: idempotency-key): idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, with Retry-After
24 h after issued_at, a wall time; the sandbox's wipe ends it sooner.
issued_at
string
yes
A wall time, such as 2026-11-05T12:00:00.000Z.
token
string
yes
For Authorization: Bearer <token>: <payload>.<mac>, both base64url, signed like the session cookie. Never in a URL: a token in a query string is refused with 400.
token_v
integer
yes
at least 0
The Sandbox's token version the token names.
This route takes the console’s cookie only, so a token cannot call it: a token never mints its successor, and a browser session is the only way to sign in.
POST/v1/sandboxes/{id}/token/rotate
Rotate: the Sandbox's token version goes up (`ApiTokenRotated`) and every older token stops
A signed-in session of sandbox {id}; a guest gets 403 guest-scope. The cookie only: an API token never mints its successor. Carries an Idempotency-Key.
Operation rotate-token · added in PR 10. A signed-in session of this sandbox; a guest gets 403 guest-scope. No token: the cookie or nothing.
Parameters
Name
In
Required
Type
Meaning
id
path
yes
string
The sandbox's ULID, from the session or the token.
Idempotency-Key
header
yes
string
A ULID, new for each intent and the same for its retries. The command's result is stored with it: the same key again answers the first result with Idempotent-Replayed: true, and the same key with a different body is 422 idempotency-key.
Answers
200TokenResponse: the new token, shown once; the same Idempotency-Key again: the first answer, replayed
400Problem (problems: idempotency-key, token): idempotency-key: no Idempotency-Key, or not a ULID; token: a cookie and a token both (both), or a token in the query string (query)
401Problem (problems: token, session): token: an API token: this route takes the session cookie only (cookie-only); session: no session, or one that does not verify
403Problem (problems: origin, guest-scope): origin: a cookie request without the storefront's exact Origin, or Sec-Fetch-Site: cross-site; guest-scope: a guest's session: sign in for this
404Problem: another sandbox's id, or one naming nothing
410Problem (problem: wiped): wiped: the sandbox is being wiped or is gone
422Problem (problem: idempotency-key): idempotency-key: the same key again with a different body
429Problem (problem: rate-limit): rate-limit: the session's or IP hash's limit, with Retry-After
24 h after issued_at, a wall time; the sandbox's wipe ends it sooner.
issued_at
string
yes
A wall time, such as 2026-11-05T12:00:00.000Z.
token
string
yes
For Authorization: Bearer <token>: <payload>.<mac>, both base64url, signed like the session cookie. Never in a URL: a token in a query string is refused with 400.
token_v
integer
yes
at least 0
The Sandbox's token version the token names.
This route takes the console’s cookie only, so a token cannot call it: a token never mints its successor, and a browser session is the only way to sign in.
The kitchen socket
GET /v1/sandboxes/{id}/kitchen/ws upgrades to a WebSocket (operationkitchen-socket). It takes the session cookie only, with the storefront’s exact Origin.
Frames are JSON text, each with "v": 1. Limits: 4 open sockets a sandbox (a fifth is told byelimit and closed with 1008), frames of at most 4 KB (1009), 10 frames a second a socket (1008), text frames only (1003). The storefront sends no ping and reconnects instead.
on open; `seq` counts the events that changed the board; `bake_lists` is one entry per bakery day from business today on, `[{date, version, lines: [{item, qty, start, catering?}], reserved}]`, `catering: true` on a catering event's line, whose `qty` is its headcount
evt
server-to-client
{t: "evt", v: 1, env, bake_list?}
each event that changed the board, the envelope whole, the note with it; and the Sandbox's `ClockAdvanced`. A `BakeListChanged`, `SlotReserved` or `SlotReleased` frame also carries `bake_list`, that day as the board holds it after the event, `{date, version, lines: [{item, qty, start, catering?}], reserved}` (since 2026-11-06; `catering` since 2026-11-08): set the day from it, do not adjust a count
presence
server-to-client
{t: "presence", v: 1, sockets}
a socket opened or closed
bye
server-to-client
{t: "bye", v: 1, reason: "wiped" | "limit"}
before the server closes: 1001 at the wipe; 1008, 1009 or 1003 at a limit
a staff action, sent to the Order with `id` as the idempotency key
ack
server-to-client
{t: "ack", v: 1, id}
the command was applied; a repeated `id` gets the first answer
nack
server-to-client
{t: "nack", v: 1, id, rule}
the command was refused, naming the rule; a guest gets `guest-scope`
ping
client-to-server
{t: "ping", v: 1}
answered `{t: "pong", v: 1}` by the platform's auto-response, which does not wake the object
pong
server-to-client
{t: "pong", v: 1}
the answer to a `ping`
Schemas
117 types, each once. A type in a table above links here.
ActivityEntry
One line of the activity log.
Name
Type
Required
Limits
Meaning
at
string
yes
summary
string
yes
A short fixed sentence from the event's named fields.
type
string
yes
ActivityResponse
GET /v1/sandboxes/{id}/activity: the sandbox's logged events (clock moves, faults, menu and capacity changes, payment intents, orders paid, catering steps, routes, traffic, token rotations, campaigns sent and rebuilds finished), newest first by business time (ties by event id); ?limit= keeps the newest that many (50 when left out, at most 500). Any session of the sandbox reads it.
Counts the plan's changes; 0 before the first reservation.
BodyTemplate
A campaign's body, chosen from a fixed list.
One of: announcement, fresh-bread, cake-orders, seasonal-menu, come-back, catering-invite.
BreakerState
The breaker's state, in the order it rises.
One of: unconfigured, armed, read-only, off.
BreakerStatus
The 15-minute cron breaker, as Control keeps it (kill switch L0; docs/cost.md, "Guardrails"). Every property is sent, null or empty when there is nothing.
Name
Type
Required
Limits
Meaning
last_run
string or null
yes
When the last run's window was handed to Control, an RFC 3339 UTC time.
last_usd
string or null
yes
The last window's usage priced in dollars with four decimals, such as "0.0123".
since
string or null
yes
When the state last changed, an RFC 3339 UTC time; null while unconfigured.
POST /v1/sandboxes/{id}/campaigns, staff only: a draft, 201 with the CampaignResponse (200 with Idempotent-Replayed: true for the same key again). PATCH /v1/sandboxes/{id}/campaigns/{cid} takes the same body and edits a draft: 200, or 409 problem of type campaign naming the rule (out-of-order) once it is scheduled, sent or cancelled. A guest gets 403guest-scope on both.
one of weekend-bake, cake-week, new-season, we-miss-you, catering-season, thank-you
CampaignState
Where a campaign is (docs/domain.md, "Campaign", the diagram).
One of: draft, scheduled, sent, cancelled.
CapacityRequest
PATCH /v1/sandboxes/{id}/schedule/{date}/capacity, signed-in sessions only: set one capacity for the day. The answer is the day's ScheduleResponse.
Name
Type
Required
Limits
Meaning
capacity
integer
yes
0 to 65535
The new capacity. Places already taken stay; a cut below them only stops new ones.
target
string
yes
What to change, in the domain's grammar: slot:HH:MM (a slot start on the quarter hour, such as slot:14:45), zone:z1 (to z3), item:<slug> (such as item:croissant) or catering.
CateringCancelReason
Why a confirmed catering event is cancelled: a choice from a list, never free text.
One of: customer_change, venue_lost, other.
CateringCancelRequest
POST /v1/sandboxes/{id}/catering/{cid}/cancel, by the customer or staff, as the session is. Only a confirmed event is cancelled: 200 with the CateringResponse, cancelled, its refund_deposit true when the event day is more than 7 days away; 409 problem of type catering naming the rule (out-of-order) in any other state.
POST /v1/sandboxes/{id}/catering, the customer's inquiry; the customer is the sandbox's persona. 201 with the CateringResponse (200 with Idempotent-Replayed: true for the same key again). A refused inquiry is 422 problem+json naming its rule: headcount, unknown-package, unknown-venue, closed-day, catering-lead (its detail names the 7-business-day rule and the earliest date allowed), or brief-too-long, brief-email, brief-phone, brief-card-number or brief-url, which never echo the brief.
Name
Type
Required
Limits
Meaning
brief
string or null
no
At most 500 characters, with no email address, phone number, card number or URL.
date
string
yes
The event day, YYYY-MM-DD: an open day (Tuesday to Sunday) at least 7 business days after today.
headcount
integer
yes
0 to 65535
10 to 200 people.
package
string
yes
A package slug, such as breakfast-spread (pastry-platter, breakfast-spread, lunch-boxes, celebration-cake-and-coffee).
venue
string
yes
A venue, v1 to v6.
CateringListResponse
GET /v1/sandboxes/{id}/catering: the sandbox's catering events, the seeded eight and any since, by date.
GET /v1/sandboxes/{id}/catering/{cid}, and the answer to every catering command: the inquiry, quote, decline, accept, cancel, and staff's production and delivered. It mirrors the CateringEvent aggregate's state. A refused step is 409 problem of type catering naming the rule (out-of-order, quote-expired); an accept when the day's two catering places are taken is 409slot-full.
Name
Type
Required
Limits
Meaning
balance_cents
integer or null
no
total_cents - deposit_cents.
brief
string or null
no
The brief, shown back to its own sandbox only, as text.
catering
string
yes
The catering event's ULID.
created_at
string
yes
The inquiry's business time.
date
string
yes
The event day, YYYY-MM-DD.
deposit_cents
integer or null
no
25% of the total, rounded half-up.
deposit_payment
string or null
no
The deposit's payment ULID, once paid.
headcount
integer
yes
0 to 65535
invoice
string or null
no
The balance invoice's ULID, once issued.
invoice_due
string or null
no
The balance invoice's due date, YYYY-MM-DD, 7 days after delivery.
package
string
yes
refund_deposit
boolean or null
no
Set on a cancellation: whether the deposit goes back.
When the quote stops being accepted, a business time: 07:00 on the 14th business day after the quote.
venue
string
yes
CateringState
A catering event's state (docs/domain.md, "CateringEvent", the diagram). paid is passed through in the same step as closed, so a response never shows it today; it is listed because the diagram has it.
CateringView
The day's catering capacity.
Name
Type
Required
Limits
Meaning
capacity
integer
yes
0 to 65535
Events the bakery takes in a day.
taken
integer
yes
0 to 65535
Events held, reserved or fulfilled.
ClockRequest
POST /v1/sandboxes/{id}/clock, signed-in sessions only: move business time forward. The offset only grows, at most 14 days in total. Give exactly one of step and minutes: step is the named step, minutes the older form (a positive count). The Worker answers 422 clock with rule not-positive for no advance or for both fields, and rule offset-cap when the 14 days would be passed.
Name
Type
Required
Limits
Meaning
minutes
integer or null
no
at least 0
The compatible older form: minutes to advance, 1 or more.
Business time now, such as 2026-11-07T09:42:10-07:00, shown at America/Denver's offset at that instant (-06:00 in summer).
clock_offset_s
integer
yes
Seconds of business time ahead of wall time, 0 to 14 days.
clock_v
integer
yes
at least 0
Counts the advances; a child that has not heard of the latest one is retried.
step
string or null
no
The step applied, in its wire form: 15m, 1h, 1d, next-opening, or <n>m for the older minutes form.
ClockStep
How far one clock advance moves business time.
One of: 15m, 1h, 1d, next-opening.
ComparisonView
The two plans' totals side by side.
Name
Type
Required
Limits
Meaning
browser_minutes
integer
yes
at least 0
gap_percent
number or null
no
double
(server − browser) / browser × 100, to one decimal: positive when the heuristic drives longer. null when the browser's plan drives 0 minutes and the server's does not.
server_minutes
integer
yes
at least 0
CompleteStopRequest
POST /v1/sandboxes/{id}/dispatch/{date}/complete, staff only: a stop of the published plan is delivered. Again for a delivered stop changes nothing. Refused 409 not-ready while the stop's order is still confirmed or in production: the kitchen marks it ready first.
Name
Type
Required
Limits
Meaning
stop
integer
yes
0 to 65535
The stop's number in the published plan, from 1.
ConsentRequest
POST /v1/sandboxes/{id}/customers/{cid}/consent, by that customer's persona or by staff: 200 with the CustomerResponse; the same value again changes nothing and answers 200.
Name
Type
Required
Limits
Meaning
marketing
boolean
yes
CountersState
How fresh counters are.
One of: live, stale, unavailable.
CreateSandboxRequest
POST /v1/sandboxes. A guest needs turnstile_token; an account that already has a live sandbox gets it back unless replace is true.
Name
Type
Required
Limits
Meaning
replace
boolean
no
turnstile_token
string or null
no
CustomerListResponse
GET /v1/sandboxes/{id}/customers: the 60 personas, by id.
GET /v1/sandboxes/{id}/customers/{cid}, and the answer to a consent change: one persona as Crm's projection holds it. Every field is synthetic; there is no contact of any kind.
Name
Type
Required
Limits
Meaning
catering
integer
yes
at least 0
Catering inquiries.
customer
string
yes
The customer's ULID.
display_name
string
yes
Two generic words, such as Drizzle Trowel.
home_zone
string
yes
z1 to z3.
last_order_at
string or null
no
The latest such order's slot, a business time.
loyalty_points
integer
yes
Loyalty points: one per whole dollar paid, less refunds; never below zero.
marketing
boolean
yes
Consent to marketing: a campaign goes only to customers for whom it is true at the send.
orders
integer
yes
at least 0
Orders paid, or closed in the seed's history, and not cancelled.
place
string
yes
p1 to p64, a map label: the only address there is.
preferences
array of string
yes
One to three item slugs.
DeadLetter
One message the Queue gave up on after 3 retries, from GET /v1/sandboxes/{id}/dead-letters (an array of these), and the answer to a redrive.
Name
Type
Required
Limits
Meaning
at
string
yes
When it was dead-lettered, a wall time.
error
string
yes
The last delivery error, as a reason code such as Kitchen answered 503.
id
string
yes
The event's ULID: the key a redrive sends it again with.
seq
integer
yes
at least 0
stream
string
yes
The producing object's name.
type
string
yes
The event type, such as OrderPlaced.
DeclineReason
Why staff decline an inquiry: a choice from a list, never free text.
One of: too_soon, over_capacity, other.
DeclineRequest
POST /v1/sandboxes/{id}/catering/{cid}/decline, staff only, while the inquiry is an inquiry. 200 with the CateringResponse, declined; 409 problem of type catering naming the rule (out-of-order) once it is quoted.
POST /v1/auth/demo. The password never reaches an object, a log or this type's Debug.
Name
Type
Required
Limits
Meaning
password
string
yes
12 to 128 characters, no composition rules.
turnstile_token
string
yes
DemoSignupResponse
201 from POST /v1/auth/demo: the generated username, shown once.
Name
Type
Required
Limits
Meaning
username
string
yes
baker- and four characters, such as baker-7f3k.
DispatchResponse
GET /v1/sandboxes/{id}/dispatch/{date}, which any session of the sandbox reads, and the answer to every dispatch command, which are staff only: one bakery day's stops and plans. It mirrors the Dispatch aggregate's state.
Name
Type
Required
Limits
Meaning
capacity
integer
yes
at least 0
Units a van carries: the last proposal's, 250 before any.
Both plans' totals, when there are both; null while the browser's solver has not run or cannot (the page then shows the server's plan alone and says why).
date
string
yes
The bakery day, YYYY-MM-DD.
plan_v
integer
yes
0 to 65535
The published plan's version, 0 before the first publish.
The sandbox's fault switches: the Queue Lab's broken subscriber, live. kitchen makes the Kitchen refuse every delivery with 503, so a message retries three times and lands in the dead-letter queue (PR 4); inbox does the same to the Inbox when it arrives (PR 8).
Name
Type
Required
Limits
Meaning
inbox
boolean
yes
kitchen
boolean
yes
FaultsResponse
The answer to a fault change: every switch as it now stands.
GET /v1/sandboxes/{id}/inbox: the newest messages first, and how many there are in all. ?kind= keeps one kind, ?to= one customer's, ?limit= the newest that many (50 when left out, at most 500). Any session of the sandbox, a guest's included, sees every customer's messages: the persona is not filtered to its own, and ?to= is how a reader narrows to one.
Stripe's id: the intent's pi_... for a payment, the refund's re_... for a refund; seed:<payment> for a seeded order's payment, which the seed made and Stripe never saw.
LedgerKind
One of: payment, refund.
LedgerResponse
GET /v1/sandboxes/{id}/billing/ledger: every entry in order, and the totals.
The map label, p1 to p64; no name, coordinate or street.
MatrixResponse
The travel-time matrix the dispatch screen loads to run VROOM. It is not an API response: it is a static asset of the web Worker, the same JSON as the committed fixture crates/seed/data/<city>/matrix.json (ADR 0012, decision 7), and this type only fixes its shape.
Name
Type
Required
Limits
Meaning
built
string
yes
When the build ran, or seed:<n> for the synthetic city.
city
string
yes
The city the build is for, or synthetic.
depot
integer
no
0 to 255
The bakery's place, where every route starts and ends; 0 when left out.
minutes
array of array of integer
yes
minutes[i][j]: whole minutes driving from place i to place j, 0 on the diagonal. Not necessarily symmetric.
PATCH /v1/sandboxes/{id}/menu/items/{slug}, signed-in sessions only. A price is a draft, set on every variant of the item, until POST .../menu/publish; a pause or a resume publishes that one item at once.
one of receipt, ready, on_its_way, refund, declined, acknowledgement, quote, notice, reminder, invoice, campaign
message
string
yes
The message's ULID.
opened_at
string or null
no
ref
string
yes
The ULID of the order, catering event or campaign it is about.
subject
string
yes
From a fixed template, filled with the event's own figures; never free text.
to
string
yes
The customer's ULID: the only recipient there is.
OrderKind
Pickup at the counter, or delivery to a zone.
One of: pickup, delivery.
OrderLineRequest
One line of an order as the customer asks for it.
Name
Type
Required
Limits
Meaning
qty
integer
yes
0 to 65535
1 to 24.
variant
string
yes
A variant slug from the menu, such as croissant/box-6.
OrderLineResponse
A placed line, priced from the menu version the order names; never repriced.
Name
Type
Required
Limits
Meaning
item
string
yes
qty
integer
yes
0 to 65535
unit_cents
integer
yes
variant
string
yes
OrderRequest
POST /v1/sandboxes/{id}/orders. The customer is the sandbox's persona; the prices come from the menu version the Catalog publishes when the order is placed.
At most 140 characters, with no email address, phone number, card number or URL.
slot
string
yes
The pickup slot's or delivery window's start, a business time such as 2026-11-07T09:45:00-07:00.
zone
string or null
no
z1, z2 or z3 for a delivery; absent for a pickup.
OrderResponse
201 from placing an order (200 with Idempotent-Replayed: true for the same key again), GET /v1/sandboxes/{id}/orders/{oid}, and the answer to a cancel.
Name
Type
Required
Limits
Meaning
events_seq
integer
yes
at least 0
The seq of the order's latest event.
held_until
string
yes
When an unpaid order expires, 15 minutes of business time after placed_at.
POST /v1/sandboxes/{id}/orders/{oid}/payment: what the browser needs to mount Stripe's Payment Element. client_secret is a one-time value for the browser: it is not stored, not logged, and left out of this type's Debug.
Name
Type
Required
Limits
Meaning
amount_cents
integer
yes
client_secret
string
yes
Stripe's pi_..._secret_..., for <Elements options={{ clientSecret }}>.
payment
string
yes
Billing's id for the payment, a ULID.
publishable_key
string or null
no
The sandbox's pk_test_ key, when the API has one to give; the storefront's own build value otherwise.
Where a payment stands (docs/domain.md, the Billing rows).
PersonaAddress
A made-up address, labelled synthetic in its first line, passed to Stripe's confirmPayment as the billing address.
Name
Type
Required
Limits
Meaning
city
string
yes
country
string
yes
An ISO 3166-1 alpha-2 code.
line1
string
yes
<place label>, unit <n> (synthetic), such as p17, unit 3 (synthetic).
postal_code
string
yes
state
string
yes
A two-letter state code.
PlanChoice
Which stored plan to publish.
One of: proposed, submitted.
PlanRequest
POST /v1/sandboxes/{id}/dispatch/{date}/plan, staff only: the plan VROOM made in the browser. It carries no minutes: the server computes them from the matrix. Refused with 422 stop-missing, stop-twice, stop-unknown, over-capacity, route-ends, vans, window or no-stops. window: the vans leave the bakery at 09:00, a van early at a door waits for the stop's window to open and spends 3 minutes there, and each stop must be reached by its window's close (StopView.window plus 120 minutes).
The place the van leaves from, as the solver reports it; it must be the bakery, and is taken to be when left out.
stops
array of string
yes
Order ULIDs, in driving order. An empty list is a van left at the bakery.
van
integer
yes
0 to 255
1 to the day's vans, each once.
PlanSource
Who made a plan: the server's savings heuristic or the browser's VROOM solver.
One of: server, browser.
PlanView
A plan as the dispatch screen shows it (ADR 0012, decision 5). Its minutes are the server's own arithmetic over the matrix, whoever made the plan.
Name
Type
Required
Limits
Meaning
last_back
string
yes
When the last van is back, a business time: the vans leave at 09:00, drive the matrix's minutes, spend 3 minutes at each door and wait at a door they reach before its window opens.
minutes
integer
yes
at least 0
Every van's drive summed.
plan_v
integer
yes
0 to 65535
A published plan's version. A proposal or submission carries the version it would be published as when it was made; one at or below the response's plan_v is stale.
The vans used, by van; a plan may use fewer than the day has.
Problem
An error body, application/problem+json (RFC 9457).
Name
Type
Required
Limits
Meaning
detail
string or null
no
What went wrong this time, for a person to read.
instance
string or null
no
The request path this occurrence concerns.
next_free
string or null
no
An extension member (RFC 9457, section 3.2), set only on the slot-full and hold-lost problems: the start of the next pickup slot with a place free that day, a business time such as 2026-11-07T10:15:00-07:00. Absent when nothing later that day is free, and on every other problem.
status
integer
yes
0 to 65535
The HTTP status code.
title
string
yes
A short summary that does not change between occurrences.
type
string
yes
A URI reference naming the problem type; about:blank when the status says it all.
ProposeRequest
POST /v1/sandboxes/{id}/dispatch/{date}/propose, staff only: the server's plan for the confirmed stops. The vans and capacity become the day's.
Name
Type
Required
Limits
Meaning
capacity
integer
yes
at least 0
Units a van carries, at least 1.
vans
integer
yes
0 to 255
1 to 4.
PublishRequest
POST /v1/sandboxes/{id}/dispatch/{date}/publish, staff only: make a stored plan the record. Checked again against the day's stops; a repeat with the same Idempotency-Key publishes nothing more.
POST /v1/sandboxes/{id}/catering/{cid}/quote, staff only. 200 with the CateringResponse, now quoted; 409 problem of type catering naming the rule (out-of-order) once the inquiry is past inquiry; 422quote-total for a total under 1 cent.
Name
Type
Required
Limits
Meaning
total_cents
integer or null
no
A staff override of the total, in cents, at least 1. Absent: the package's price per head times the headcount. The deposit is 25% of the total, rounded half-up.
RebuildResponse
GET /v1/sandboxes/{id}/rebuild, which any session of the sandbox reads, and 202 from POST to it, staff only (a guest gets 403guest-scope): "Rebuild projections" drops Crm's projections and replays its log, 200 events per alarm. A second POST (with a new Idempotency-Key) while one runs is 409 problem of type rebuild and starts nothing; the same key again replays the first 202. Nothing else is refused during a rebuild: other commands run, reads answer the partial projection with Projection-State: rebuilding, and a campaign send that falls due is deferred (logged as sends_deferred) until it ends. GET says how far the running one is, and finished with its ms until the next start.
Name
Type
Required
Limits
Meaning
applied
integer
yes
at least 0
Log entries replayed so far.
ms
integer or null
no
at least 0
Once finished: the wall-clock milliseconds the rebuild took.
Why staff give money back: a choice from a list, never free text (docs/domain.md, "Free text and personal data"). The other two reasons the domain knows, cancelled and payment_late, are the system's own.
One of: missing_item, quality, goodwill.
RefundRequest
POST /v1/sandboxes/{id}/orders/{oid}/refund, staff only. No amount_cents refunds all that is left; refunding all that is left of an order not yet closed cancels it.
A sandbox's lifecycle (docs/domain.md, "Sandbox").
ScheduleRequest
POST /v1/sandboxes/{id}/campaigns/{cid}/schedule, staff only: 200 with the CampaignResponse, now scheduled. A send_at less than 15 minutes of business time after now is 422 problem naming schedule-too-soon, its detail the earliest time allowed; a campaign not in draft is 409campaign naming out-of-order. POST .../campaigns/{cid}/cancel (no body) takes a scheduled campaign back to draft and a draft to cancelled; a sent one is 409campaign naming out-of-order.
Name
Type
Required
Limits
Meaning
send_at
string
yes
A business time, such as 2026-11-08T09:00:00-07:00.
ScheduleResponse
GET /v1/sandboxes/{id}/schedule/{date}, and the answer to a capacity change: one bakery day's places, caps and bake list. It mirrors the Schedule aggregate's state.
GET /v1/sandboxes/{id}/segments/{segment}: how many customers the rule holds now, and a few of their ids. Consent is not applied here; a send applies it. An unknown segment is 404.
capacity minus taken, 0 when over-booked after a capacity cut.
start
string
yes
The slot's start, a business time such as 2026-07-14T14:45:00-06:00.
taken
integer
yes
0 to 65535
Places held, reserved or fulfilled; released places do not count. Capped at 65,535.
StatusCounters
The status page's counters: the kept Analytics Engine queries over the last 24 hours, and the last nightly wipe (docs/operations.md, "Observability"). Counts are sums of the points' sample intervals, so they stay counts when Analytics Engine samples.
Name
Type
Required
Limits
Meaning
dlq_24h
integer
yes
at least 0
dlq points in the last 24 hours: messages the dead-letter writer kept.
The latest wipe point; null when none is in the dataset.
orders_24h
integer
yes
at least 0
order_placed points in the last 24 hours.
payment_failures_24h
integer
yes
at least 0
payment_failed points in the last 24 hours.
payments_24h
integer
yes
at least 0
payment_succeeded points in the last 24 hours.
refunds_24h
integer
yes
at least 0
refund_issued points in the last 24 hours.
sandboxes_24h
integer
yes
at least 0
sandbox_created points in the last 24 hours, to read against the daily cap.
StatusResponse
GET /v1/status: today's admission state, from the Control object. The field order is fixed and is the wire order: the day and the sandbox count and cap (PR 2), then the guest and demo-account counts and caps (PR 3), then the status page's counters with their time and state (PR 13), then the breaker's state (PR 17), then the flag. Readers go by name, so PR 2's smoke check still passes; a new field is added before flag. The counters are a snapshot of the kept Analytics Engine queries that the 15-minute cron refreshes, never a query per request (docs/operations.md, "Observability").
The stop's number in the published plan, counted from 1 across the vans, van 1's stops first; null when it is in no published plan.
units
integer
yes
at least 0
The order's line quantities summed: what the stop takes of a van's capacity.
van
integer or null
no
0 to 255
The van that carries it in the published plan; null when none does.
window
string
yes
The delivery window's start, a business time (RFC 3339 with the bakery's offset). The window is 2 hours long: it closes 120 minutes after this. A plan must reach the stop between the two, waiting at the door when it is early (rule window).
zone
string
yes
z1, z2 or z3.
SubjectTemplate
A campaign's subject, chosen from a fixed list; staff never type one (Q14).
One of: weekend-bake, cake-week, new-season, we-miss-you, catering-season, thank-you.
TimelineEntry
One line of a timeline.
Name
Type
Required
Limits
Meaning
at
string
yes
The event's business time.
label
string
yes
A short fixed sentence with the event's own figures, such as Paid $22.00.
ref
string
yes
The ULID of the order, catering event, message or customer the line is about.
type
string
yes
The event's catalog name, such as OrderPaid.
TimelineResponse
GET /v1/sandboxes/{id}/customers/{cid}/timeline: the customer's events in business-time order. While a rebuild runs the timeline is partial; GET .../rebuild says so.
GET /v1/sandboxes/{id}/token: what the console shows about the token without the token.
Name
Type
Required
Limits
Meaning
expires_at
string or null
no
When that token stops being accepted, a wall time.
issued_at
string or null
no
When the last token at this version was issued, a wall time; absent before the first issue and after a rotation until the next.
masked
string or null
no
That token's first 6 and last 4 characters around …, such as eyJ2Ij…x7Qk: enough to tell two tokens apart, never enough to use one.
token_v
integer
yes
at least 0
The Sandbox's token version: a token naming an older one is refused.
TokenResponse
POST /v1/sandboxes/{id}/token (issue, or issue again at the same version) and POST /v1/sandboxes/{id}/token/rotate (the Sandbox's token version goes up, ApiTokenRotated is appended, and every token naming an older version stops at once): the token, shown this once. It is never stored, logged, put in an event or printed by this type's Debug; the console holds it in memory to copy it.
Name
Type
Required
Limits
Meaning
expires_at
string
yes
24 h after issued_at, a wall time; the sandbox's wipe ends it sooner.
issued_at
string
yes
A wall time, such as 2026-11-05T12:00:00.000Z.
token
string
yes
For Authorization: Bearer <token>: <payload>.<mac>, both base64url, signed like the session cookie. Never in a URL: a token in a query string is refused with 400.
token_v
integer
yes
at least 0
The Sandbox's token version the token names.
TrafficRequest
POST /v1/sandboxes/{id}/traffic, signed-in sessions only: simulated orders a minute.
Name
Type
Required
Limits
Meaning
rate
integer
yes
0 to 255
1 to 6.
TrafficResponse
GET /v1/sandboxes/{id}/traffic, and the answer to starting or stopping it.
Name
Type
Required
Limits
Meaning
minutes_left
integer
yes
0 to 65535
What is left of the day's cap, 30 minutes (docs/cost.md, "Guardrails").
minutes_used
integer
yes
0 to 65535
Minutes of traffic this sandbox used today, UTC.
orders
integer
yes
0 to 65535
Orders the simulator placed today.
rate
integer
yes
0 to 255
Orders a minute of the current or last run; 0 before the first start.
running
boolean
yes
VanPlanView
One van of a plan.
Name
Type
Required
Limits
Meaning
minutes
integer
yes
at least 0
The drive, bakery to bakery, from the travel-time matrix.
stops
array of string
yes
Order ULIDs, in driving order.
units
integer
yes
at least 0
The stops' units summed; never over the day's capacity.
van
integer
yes
0 to 255
1 to the day's vans.
WipedResponse
DELETE /v1/sandboxes/{id}, "Wipe now": the sandbox is gone when this answers.