Endpoints
Sessions
Bearer-token auth; roles are owner, manager, viewer, admin.POST /api/session | {email, password} → {token, role, name, merchantID} · 401 on invalid credentials |
|---|---|
GET /api/me | Current identity + merchant record |
Merchant
Own resources only — cross-merchant access 404s by design.GET/PUT /api/storefront | Profile, storefront, hours, menu |
|---|---|
GET/POST /api/offers | Offers; creation always lands as a draft |
POST /api/offers/:id/publish | Requires {confirmReviewed: true} — 422 otherwise; draft→published only |
POST /api/offers/:id/retire | published → retired |
GET/POST /api/campaigns | Objectives → eligibility rules |
GET /api/orders · PATCH /api/orders/:id | accept | reject | fulfill | refund — legal transitions only, 409 on violation |
GET /api/analytics | Orders, revenue, commission, per-offer conversion |
GET /api/payouts | Commission statements (sandbox-labeled until a payment provider exists) |
POST /api/assistant/draft | {goal} → labeled AI draft; drafts are never auto-published |
GET /api/audit | Own audit trail |
Public (traveler surfaces)
Only verified merchants' live offers ever appear.GET /api/public/offers | published ∧ started ∧ unexpired ∧ under cap ∧ merchant verified ∧ not suspended |
|---|---|
GET /api/public/storefront/:merchantID | Verified merchant storefront |
POST /api/public/orders | Idempotent on idempotencyKey — resubmission returns the original order |
GET /api/public/orders/:id | Order + full status history |
Admin
Role admin: verification lifecycle, moderation, flags, health, global audit.POST /api/admin/merchants/:id/(verify|suspend|reinstate) | Merchant lifecycle |
|---|---|
POST /api/admin/offers/:id/(suspend|reinstate) | Platform moderation — suspension removes offers from the public feed immediately |
GET /api/admin/health · /flags · /audit | Ops surface |
Quick start
# Live offers near the traveler (public, no session in sandbox)
curl "$BASE_URL/api/public/offers"
# Submit an order — idempotent, safe to retry
curl -X POST "$BASE_URL/api/public/orders" \
-H "content-type: application/json" \
-d '{
"offerID": "offer_tacoloco_tuesday",
"items": [{ "name": "Street tacos", "priceCents": 1450, "qty": 1 }],
"idempotencyKey": "d290f1ee-6c54-4b01-90e6-d701748f0851"
}'const res = await fetch(`${BASE_URL}/api/session`, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ email, password }),
});
const { token } = await res.json();
// Publish an offer — the contract forces explicit review
await fetch(`${BASE_URL}/api/offers/${offerId}/publish`, {
method: "POST",
headers: {
authorization: `Bearer ${token}`,
"content-type": "application/json",
},
body: JSON.stringify({ confirmReviewed: true }),
});Contract invariants
Guarantees the test suite enforces.
These aren’t docs promises — each one is covered by the platform’s API contract tests.
- Draft offers never appear publicly; publishing requires explicit merchant review confirmation.
- Order transitions follow the state machine — no skipping merchant acceptance.
- Merchants cannot read or mutate other merchants' resources (404-scoped).
- Admin suspension removes a merchant's offers from the public feed immediately.
- Idempotency keys deduplicate order submissions.
- AI assistant output is labeled fixture/live and only ever produces drafts.
- All money is integer cents USD. Sensitive actions append to the audit log.
Questions about integrating a POS or booking system? Start with the Partner Program.