{"openapi":"3.1.0","info":{"title":"Stagera Public API","version":"2.5.0","description":"REST API for Stagera event production SaaS. Multi-tenant, API-key authenticated, cursor-paginated. Deprecation policy: /api/v2/* is stable; breaking changes ship under /api/v3/* with a minimum 6-month overlap window and Sunset headers.","contact":{"email":"support@stagera.ai"}},"servers":[{"url":"https://dkgkqkkoqriebjlaufcx.supabase.co/functions/v1/api/v2","description":"Production (recommended for server-to-server integrations)"},{"url":"https://app.stagera.ai/api/v2","description":"Branded alias (note: Vercel bot protection may challenge non-browser clients -- use the direct URL for scripted calls)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API Key","description":"Per-org API key in the form `stg_live_...` or `stg_test_...` (legacy `sk_live_...` also accepted). Create keys in Settings."}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","request_id"],"properties":{"code":{"type":"string","example":"invalid_credentials"},"message":{"type":"string"},"details":{"type":"object","nullable":true},"request_id":{"type":"string","format":"uuid"}}}}},"Pagination":{"type":"object","required":["next_cursor","has_more"],"properties":{"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}}},"Event":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string"},"start_date":{"type":"string","format":"date-time"},"end_date":{"type":"string","format":"date-time"},"venue":{"type":"string"},"client_id":{"type":"string","format":"uuid","nullable":true},"created_at":{"type":"string","format":"date-time"}}},"Client":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"email":{"type":"string","format":"email","nullable":true},"phone":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"}}},"Category":{"type":"object","description":"Equipment category. Returned inline when `/equipment` is requested with `?expand=category`.","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"color":{"type":"string","nullable":true,"description":"Hex color code for case/category labeling (e.g. `#03DAC6`). Used by downstream integrations like TruckPacker to color-code cases."}}},"Equipment":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"brand":{"type":"string","nullable":true},"category_id":{"type":"string","format":"uuid","nullable":true},"stock_quantity":{"type":"integer","nullable":true},"daily_rate":{"type":"number","nullable":true},"case_length_in":{"type":"number","nullable":true,"description":"Case length in inches (use for load planning)"},"case_width_in":{"type":"number","nullable":true,"description":"Case width in inches (use for load planning)"},"case_height_in":{"type":"number","nullable":true,"description":"Case height in inches (use for load planning)"},"weight_lbs":{"type":"number","nullable":true,"description":"Case weight in pounds (use for payload calculations)"},"created_at":{"type":"string","format":"date-time"}}},"Vehicle":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"model":{"type":"string","nullable":true},"license_plate":{"type":"string","nullable":true},"vehicle_type":{"type":"string","nullable":true},"status":{"type":"string"},"interior_length_inches":{"type":"integer","nullable":true},"interior_width_inches":{"type":"integer","nullable":true},"interior_height_inches":{"type":"integer","nullable":true},"max_payload_lbs":{"type":"integer","nullable":true},"created_at":{"type":"string","format":"date-time"}}},"EquipmentReservation":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"equipment_id":{"type":"string","format":"uuid"},"event_id":{"type":"string","format":"uuid","nullable":true},"vehicle_id":{"type":"string","format":"uuid","nullable":true},"truck_position":{"type":"string","nullable":true},"start_date":{"type":"string","format":"date-time"},"end_date":{"type":"string","format":"date-time"},"quantity":{"type":"integer"},"reservation_status":{"type":"string"},"created_at":{"type":"string","format":"date-time"}}},"Quote":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"quote_number":{"type":"string"},"title":{"type":"string"},"status":{"type":"string"},"total_amount":{"type":"number"},"client_id":{"type":"string","format":"uuid","nullable":true},"created_at":{"type":"string","format":"date-time"}}},"Invoice":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"invoice_number":{"type":"string"},"title":{"type":"string"},"status":{"type":"string"},"total_amount":{"type":"number"},"client_id":{"type":"string","format":"uuid","nullable":true},"created_at":{"type":"string","format":"date-time"}}},"CrewMember":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"first_name":{"type":"string"},"last_name":{"type":"string"},"email":{"type":"string","format":"email","nullable":true},"is_active":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"}}},"PickList":{"type":"object","description":"A pick list is the warehouse manifest of equipment for an event/job. Generated automatically when a quote is approved, or created manually. Primary resource for TruckPacker: use `GET /pick_lists?event_id=<job>` to pull every case/item for a job in one call.","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string","description":"`draft` | `in_progress` | `packed` | `complete`"},"event_id":{"type":"string","format":"uuid","nullable":true},"quote_id":{"type":"string","format":"uuid","nullable":true},"archived":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"items":{"type":"array","description":"Line items with the equipment + quantity manifest. Always included on `GET /pick_lists/{id}`; request on `GET /pick_lists` via `?expand=items`.","items":{"$ref":"#/components/schemas/PickListItem"},"nullable":true}}},"PickListItem":{"type":"object","description":"One equipment line on a pick list. `quantity` is how many the event needs; `stage` progresses through the warehouse workflow (`pending` | `checked` | `staged` | `loaded` | `installing` | `installed`). Container hierarchy: when `is_container=true`, other items reference this row via `parent_item_id`/`container_id`.","properties":{"id":{"type":"string","format":"uuid"},"pick_list_id":{"type":"string","format":"uuid"},"equipment_id":{"type":"string","format":"uuid","nullable":true},"quantity":{"type":"integer"},"stage":{"type":"string"},"notes":{"type":"string","nullable":true},"custom_description":{"type":"string","nullable":true,"description":"Free-text description used when the line doesn't map to an equipment record (typically one-off custom items)."},"is_container":{"type":"boolean","nullable":true},"container_id":{"type":"string","format":"uuid","nullable":true,"description":"FK to the containers table when this pick-list item represents a physical case with contents."},"is_package":{"type":"boolean","nullable":true},"parent_item_id":{"type":"string","format":"uuid","nullable":true,"description":"Self-FK: when this item lives inside another pick-list row (container/package hierarchy), points to the parent."},"serial_numbers":{"type":"array","items":{"type":"string"},"nullable":true,"description":"Serialized-unit serial codes assigned to this line, when the equipment is tracked serially."},"warehouse_id":{"type":"string","format":"uuid","nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"equipment":{"type":"object","nullable":true,"description":"Inlined equipment record when the request used `?expand=equipment`. Includes case dimensions and weight for load planning. When `?expand=equipment,category` is requested, also includes a nested `category` object (id, name, color).","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"brand":{"type":"string","nullable":true},"category_id":{"type":"string","format":"uuid","nullable":true},"case_length_in":{"type":"number","nullable":true},"case_width_in":{"type":"number","nullable":true},"case_height_in":{"type":"number","nullable":true},"weight_lbs":{"type":"number","nullable":true},"daily_rate":{"type":"number","nullable":true},"category":{"type":"object","nullable":true,"description":"Inlined equipment_categories record when the request used `?expand=equipment,category`.","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"color":{"type":"string","nullable":true,"description":"Hex color (e.g. `#1a73e8`) for UI grouping."}}}}}}}}},"paths":{"/health":{"get":{"summary":"Health + diagnostic","description":"Returns request_id, organization_id, scopes, sandbox state, and current rate-limit bucket. Requires any valid API key.","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"schema":{"type":"string","format":"uuid"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"string","format":"date-time"}}},"content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/events":{"get":{"summary":"List events","description":"Returns a cursor-paginated list of events for the key's organization.","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":25,"minimum":1,"maximum":100}},{"name":"cursor","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"schema":{"type":"string","format":"uuid"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"string","format":"date-time"}}},"content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Event"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}},"post":{"summary":"Create event","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","start_date","end_date","venue"],"properties":{"name":{"type":"string"},"start_date":{"type":"string","format":"date-time"},"end_date":{"type":"string","format":"date-time"},"venue":{"type":"string"},"client_id":{"type":"string","format":"uuid","nullable":true},"status":{"type":"string","default":"inquiry"},"description":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Event"}}}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/events/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"summary":"Get event","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Event"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"summary":"Update event","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Event"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/jobs":{"get":{"summary":"List jobs (alias of /events)","description":"Alias route for clients that use the 'jobs' terminology (e.g. Truck Packer). Accepts `events:read` OR legacy `jobs:read` scope.","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":25,"minimum":1,"maximum":100}},{"name":"cursor","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Event"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}}},"/clients":{"get":{"summary":"List clients","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":25,"minimum":1,"maximum":100}},{"name":"cursor","in":"query","schema":{"type":"string"}},{"name":"search","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Client"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}},"post":{"summary":"Create client","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"email":{"type":"string","format":"email","nullable":true},"phone":{"type":"string","nullable":true},"address":{"type":"string","nullable":true},"city":{"type":"string","nullable":true},"state":{"type":"string","nullable":true},"zip":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Client"}}}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/clients/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"summary":"Get client","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Client"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"summary":"Update client","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Client"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/equipment":{"get":{"summary":"List equipment","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":25,"minimum":1,"maximum":100}},{"name":"cursor","in":"query","schema":{"type":"string"}},{"name":"category","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Equipment"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}}},"/equipment/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"summary":"Get equipment","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Equipment"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/vehicles":{"get":{"summary":"List assignable vehicles","description":"Returns available fleet vehicles for the key's organization. Requires `equipment_reservations:read`.","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":25,"minimum":1,"maximum":100}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"schema":{"type":"string","format":"uuid"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"string","format":"date-time"}}},"content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Vehicle"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/vehicles/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"summary":"Get assignable vehicle","description":"Returns a single available fleet vehicle for the key's organization.","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"schema":{"type":"string","format":"uuid"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"string","format":"date-time"}}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Vehicle"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/pick_list_items":{"post":{"summary":"Add a case to a pick list","description":"On-site additions that weren't in the original quote. Either `equipment_id` (references a real equipment row) or `custom_description` (free-text line) is required.","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["pick_list_id"],"properties":{"pick_list_id":{"type":"string","format":"uuid"},"equipment_id":{"type":"string","format":"uuid","nullable":true},"custom_description":{"type":"string","nullable":true},"quantity":{"type":"integer","default":1},"stage":{"type":"string","default":"pending"},"notes":{"type":"string","nullable":true}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/PickListItem"}}}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/pick_list_items/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"patch":{"summary":"Update a pick list item (stage / quantity / notes)","description":"Advance `stage` through the warehouse workflow (`pending` → `checked` → `staged` → `loaded` → `installing` → `installed`) or update `quantity`, `notes`, `custom_description`.","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/PickListItem"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Remove a pick list item","responses":{"204":{"description":"Deleted"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/pick_lists":{"get":{"summary":"List pick lists (cases per job)","description":"Returns warehouse pick lists, optionally filtered by event/job. Use `?event_id=<job_id>` to get every case-manifest entry for a job, primary integration point for TruckPacker's per-job import.\n\nScope: `pick_lists:read`. Legacy keys with `events:read` or `jobs:read` are also accepted so existing integrations keep working.","parameters":[{"name":"event_id","in":"query","schema":{"type":"string","format":"uuid"},"description":"Filter to pick lists for a specific event/job."},{"name":"status","in":"query","schema":{"type":"string"},"description":"`draft` | `in_progress` | `packed` | `complete`."},{"name":"archived","in":"query","schema":{"type":"boolean"},"description":"Include archived pick lists. Defaults to `false`."},{"name":"expand","in":"query","schema":{"type":"string"},"description":"Comma-separated: `event`, `items`, `equipment`, `category`. `equipment` only takes effect when combined with `items` and nests the full equipment record (name, brand, case dims, weight, daily_rate) under each item, saving a per-line `GET /equipment/{id}` round-trip. `category` requires `equipment` (and `items` on the list endpoint) and nests the equipment_categories record (id, name, color) one level deeper, so the full case + dims + category breakdown comes back in a single call."},{"name":"limit","in":"query","schema":{"type":"integer","default":25,"maximum":100}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"schema":{"type":"string","format":"uuid"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"string","format":"date-time"}}},"content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PickList"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}}},"/pick_lists/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"summary":"Get a pick list with its items","description":"Returns the pick list and its full item manifest (equipment, quantity, stage, container hierarchy). `items` is always included on detail, no expand required. Add `?expand=equipment` to nest the full equipment record (name, brand, case dims, weight, daily_rate) under each item; add `?expand=equipment,category` to also nest the equipment_categories record (id, name, color) inside each equipment, so a single call returns the entire case + dims + category breakdown.","parameters":[{"name":"expand","in":"query","schema":{"type":"string"},"description":"Comma-separated. `equipment` inlines equipment under each item; `category` (requires `equipment`) nests equipment_categories inside each equipment."}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/PickList"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"summary":"Update a pick list (status / name / notes)","description":"Typical TruckPacker flow: flip `status` from `draft` → `in_progress` when packing starts, then to `packed` or `complete` when done.","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/PickList"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/equipment_reservations":{"get":{"summary":"List equipment reservations (truck assignments)","description":"List every reservation your integration has written. `?event_id=<job_id>` scopes to one job, the common case for re-hydrating a truck-pack plan when the user reopens a job in TruckPacker. `?expand=equipment,event,vehicle` inlines the three FK relations so you don't need per-row lookups.","parameters":[{"name":"event_id","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"vehicle_id","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","schema":{"type":"string"}},{"name":"expand","in":"query","schema":{"type":"string"},"description":"Comma-separated: `equipment`, `event`, `vehicle`."},{"name":"limit","in":"query","schema":{"type":"integer","default":25,"maximum":100}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"schema":{"type":"string","format":"uuid"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"string","format":"date-time"}}},"content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EquipmentReservation"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}},"post":{"summary":"Create equipment reservation","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["equipment_id","start_date","end_date"],"properties":{"equipment_id":{"type":"string","format":"uuid"},"event_id":{"type":"string","format":"uuid","nullable":true},"vehicle_id":{"type":"string","format":"uuid","nullable":true},"truck_position":{"type":"string","nullable":true,"maxLength":120},"start_date":{"type":"string","format":"date-time"},"end_date":{"type":"string","format":"date-time"},"quantity":{"type":"integer","default":1},"notes":{"type":"string","nullable":true},"force_overbook":{"type":"boolean","description":"Optional override. Set to `true` to allow this reservation to exceed available stock. Requires `overbook_reason`. When the server-side stock guard is in BLOCK mode (Stage D), omitting this on an overbooking attempt returns 422 with `error.code = overbook_blocked` and a structured deficit payload."},"overbook_reason":{"type":"string","minLength":4,"description":"Required when `force_overbook=true`. Short audit string (>= 4 chars) explaining why the overbook is acceptable."},"overbook_cost_ownership":{"type":"string","enum":["new_customer","original_customer","absorbed"],"description":"Who absorbs the cost of resolving the overbook (sub-rental, shortfall, etc.)."}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/EquipmentReservation"}}}}}},"409":{"description":"Duplicate record. `error.code = duplicate_record`. Triggered when an equipment is already reserved for the given event; integrator should treat this as 'already exists' rather than retrying.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation error. Notable codes:\n- `overbook_blocked`: This reservation would exceed available stock. Response `details` includes `requested`, `available`, `deficit`, `conflicting_event_ids`, `conflicting_reservation_ids`, `window_start`, `window_end`, and a `retry_with` hint. Retry with `force_overbook=true` + `overbook_reason` to accept.\n- `overbook_reason_required`: `force_overbook=true` was set without a 4+ character `overbook_reason`.\n- `validation_error`: missing required fields, invalid dates, cross-tenant FK, etc.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/equipment_reservations/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"summary":"Get a single reservation","parameters":[{"name":"expand","in":"query","schema":{"type":"string"},"description":"Comma-separated: `equipment`, `event`, `vehicle`."}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/EquipmentReservation"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"summary":"Update reservation","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"force_overbook":{"type":"boolean","description":"Optional override to allow this PATCH (typically a quantity bump) to exceed available stock. Requires `overbook_reason`."},"overbook_reason":{"type":"string","minLength":4,"description":"Required when `force_overbook=true`. Short audit string (>= 4 chars)."},"overbook_cost_ownership":{"type":"string","enum":["new_customer","original_customer","absorbed"]}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/EquipmentReservation"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation error. See POST `/equipment_reservations` for `overbook_blocked` / `overbook_reason_required` semantics.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Delete reservation","responses":{"204":{"description":"Deleted"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/quotes":{"get":{"summary":"List quotes","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":25,"minimum":1,"maximum":100}},{"name":"cursor","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Quote"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}},"post":{"summary":"Create quote","description":"Creates a quote. `quote_number` is auto-generated if omitted.","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title"],"properties":{"title":{"type":"string"},"quote_number":{"type":"string","nullable":true},"client_id":{"type":"string","format":"uuid","nullable":true},"event_id":{"type":"string","format":"uuid","nullable":true},"status":{"type":"string","default":"draft"},"notes":{"type":"string","nullable":true},"internal_notes":{"type":"string","nullable":true},"quote_type":{"type":"string","default":"rental"}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Quote"}}}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/quotes/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"summary":"Get quote (with line items)","parameters":[{"name":"expand","in":"query","description":"Comma-separated relations: client, event","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Quote"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"summary":"Update quote","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Quote"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/invoices":{"get":{"summary":"List invoices","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":25,"minimum":1,"maximum":100}},{"name":"cursor","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Invoice"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}},"post":{"summary":"Create invoice","description":"Creates an invoice. `invoice_number` is auto-generated if omitted.","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["due_date"],"properties":{"due_date":{"type":"string","format":"date"},"issue_date":{"type":"string","format":"date","nullable":true},"invoice_number":{"type":"string","nullable":true},"client_id":{"type":"string","format":"uuid","nullable":true},"event_id":{"type":"string","format":"uuid","nullable":true},"status":{"type":"string","default":"draft"},"notes":{"type":"string","nullable":true}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Invoice"}}}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/invoices/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"summary":"Get invoice (with line items)","parameters":[{"name":"expand","in":"query","description":"Comma-separated relations: client, event","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Invoice"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"summary":"Update invoice","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Invoice"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/crew_members":{"get":{"summary":"List crew members","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":25,"minimum":1,"maximum":100}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CrewMember"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}},"post":{"summary":"Create crew member","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["first_name","last_name"],"properties":{"first_name":{"type":"string"},"last_name":{"type":"string"},"email":{"type":"string","format":"email","nullable":true},"phone":{"type":"string","nullable":true},"is_active":{"type":"boolean","default":true},"notes":{"type":"string","nullable":true}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/CrewMember"}}}}}},"422":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/crew_members/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"summary":"Get crew member","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/CrewMember"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"summary":"Update crew member","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/CrewMember"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}