Update an experience, or archive/restore it
/api/experiences/{id}Two shapes in one route, same posture PATCH /api/products/{id} takes. A body of exactly {"archived": true|false} sets/clears archived_at and returns immediately, no other field required. Any other body is a full replacement of the catalog fields (parseExperienceInput's contract). RLS scopes the update, so an id from another org matches zero rows and returns 404.
Authorization
sessionCookie The dashboard's Supabase Auth session cookie, set at sign-in. Large sessions are split across
numbered chunks (…auth-token.0, .1), so treat this as a cookie family rather than one name.
Every request re-validates it against the Auth server (getUser()), never by decoding the cookie
locally: a JWT nothing has checked is not a credential. Tenancy is then read from the verified
app_metadata.company_id claim and enforced by row-level security; it is never read from request
input, on any route, ever.
role (admin / staff) is deliberately not in RLS. It gates specific actions in route code,
the operations marked admin below, so hiding a button in the UI is cosmetic only, and a route's
own check is the enforcement.
In: cookie
Path Parameters
Experience id.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
curl -X PATCH "https://example.com/api/experiences/string" \ -H "Content-Type: application/json" \ -d '{ "archived": true }'{ "ok": true}Create an experience POST
Adds a special night, set menu or ticketed event to the catalog. `company_id` comes from the verified JWT claim, never the body.
Upload an experience image POST
Stores the file at `{companyId}/{experienceId}` in the `experience-images` bucket and writes a cache-busted public URL onto the experience row. Not gated on `manage_services`: a photo is part of editing the experience, same posture as the equivalent product-image route. Ownership is checked BEFORE the upload, so a request naming an experience the caller does not own is a 404 with nothing written.