Update a service
/api/services/{id}Full replacement of the service's editable fields; despite the verb, every field in the schema is written on every call, so a partial body resets what it omits. RLS scopes the update, so an id from another org simply 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
Service 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/services/string" \ -H "Content-Type: application/json" \ -d '{ "name": "string", "durationMinutes": 5, "color": "string" }'{ "ok": true}Reorder and/or regroup services PATCH
The body is one category's (or "Uncategorized"'s, via a null groupId) full shelf in its new order: position in the array becomes the new `sort_order`, and every listed id is written to `groupId`. A drag that only reorders within one category sends that category's own id back unchanged; a drag that moves a service into a different (or no) category sends the destination's id and its full resulting id list, including whichever service just arrived from elsewhere, so this one request is the only write a cross-category move needs. Same shape as PATCH /api/service-groups; an id that is not this org's simply matches zero rows under RLS.
Delete a service (admin, or manage_services) DELETE
Hard delete. The foreign key from `book_appointments` has no cascade on purpose, so a service with booking history cannot be deleted; deactivate it instead (`active: false`). Gated to admin, or a staff login granted `manage_services` (migration 0082): price, duration and every other service setting is a delegable business decision now.