{"openapi":"3.1.0","info":{"title":"Kitorium Quotes Public API","version":"1.0.0","description":"The Kitorium Quotes Public REST API.  Authenticate with a `kit_<env>_*` Bearer token from your tenant Settings → Developer page."},"servers":[{"url":"https://api.quotes.kitorium.com","description":"production"},{"url":"http://fymsfdgnuwzixgajvltu.supabase.co/functions/v1/v1-api","description":"this preview"}],"paths":{"/v1/ping":{"get":{"summary":"Proof-of-life check.  Returns the tenant your key resolves to.","tags":["system"],"security":[{"bearerApiKey":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true},"tenant_id":{"type":"string","format":"uuid"},"version":{"type":"string"}},"required":["ok","tenant_id","version"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/customers":{"get":{"summary":"List customers. Cursor-paginated; search matches name / phone / email.","tags":["customers"],"security":[{"bearerApiKey":["customers:read"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"phone":{"type":"string"},"email":{"oneOf":[{"type":"string"},{"type":"null"}]},"address_line1":{"oneOf":[{"type":"string"},{"type":"null"}]},"address_line2":{"oneOf":[{"type":"string"},{"type":"null"}]},"address_city":{"oneOf":[{"type":"string"},{"type":"null"}]},"address_state":{"oneOf":[{"type":"string"},{"type":"null"}]},"address_zip":{"oneOf":[{"type":"string"},{"type":"null"}]},"notes":{"oneOf":[{"type":"string"},{"type":"null"}]},"archived_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","tenant_id","name","phone","email","address_line1","address_line2","address_city","address_state","address_zip","notes","archived_at","created_at","updated_at"],"additionalProperties":false}},"next_cursor":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["data","next_cursor"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"post":{"summary":"Create a customer.","tags":["customers"],"security":[{"bearerApiKey":["customers:write"]}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"phone":{"type":"string"},"email":{"oneOf":[{"type":"string"},{"type":"null"}]},"address_line1":{"oneOf":[{"type":"string"},{"type":"null"}]},"address_line2":{"oneOf":[{"type":"string"},{"type":"null"}]},"address_city":{"oneOf":[{"type":"string"},{"type":"null"}]},"address_state":{"oneOf":[{"type":"string"},{"type":"null"}]},"address_zip":{"oneOf":[{"type":"string"},{"type":"null"}]},"notes":{"oneOf":[{"type":"string"},{"type":"null"}]},"archived_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","tenant_id","name","phone","email","address_line1","address_line2","address_city","address_state","address_zip","notes","archived_at","created_at","updated_at"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"phone":{"type":"string","pattern":"^\\+[1-9][0-9]{1,14}$"},"email":{"oneOf":[{"type":"string","format":"email"},{"type":"null"}]},"address_line1":{"oneOf":[{"type":"string","maxLength":200},{"type":"null"}]},"address_line2":{"oneOf":[{"type":"string","maxLength":200},{"type":"null"}]},"address_city":{"oneOf":[{"type":"string","maxLength":100},{"type":"null"}]},"address_state":{"oneOf":[{"type":"string","maxLength":100},{"type":"null"}]},"address_zip":{"oneOf":[{"type":"string","maxLength":20},{"type":"null"}]},"notes":{"oneOf":[{"type":"string","maxLength":4000},{"type":"null"}]}},"required":["name","phone"],"additionalProperties":false}}}}}},"/v1/customers/{id}":{"get":{"summary":"Retrieve a single customer.","tags":["customers"],"security":[{"bearerApiKey":["customers:read"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"phone":{"type":"string"},"email":{"oneOf":[{"type":"string"},{"type":"null"}]},"address_line1":{"oneOf":[{"type":"string"},{"type":"null"}]},"address_line2":{"oneOf":[{"type":"string"},{"type":"null"}]},"address_city":{"oneOf":[{"type":"string"},{"type":"null"}]},"address_state":{"oneOf":[{"type":"string"},{"type":"null"}]},"address_zip":{"oneOf":[{"type":"string"},{"type":"null"}]},"notes":{"oneOf":[{"type":"string"},{"type":"null"}]},"archived_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","tenant_id","name","phone","email","address_line1","address_line2","address_city","address_state","address_zip","notes","archived_at","created_at","updated_at"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"patch":{"summary":"Partially update a customer. Unspecified fields stay unchanged.","tags":["customers"],"security":[{"bearerApiKey":["customers:write"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"phone":{"type":"string"},"email":{"oneOf":[{"type":"string"},{"type":"null"}]},"address_line1":{"oneOf":[{"type":"string"},{"type":"null"}]},"address_line2":{"oneOf":[{"type":"string"},{"type":"null"}]},"address_city":{"oneOf":[{"type":"string"},{"type":"null"}]},"address_state":{"oneOf":[{"type":"string"},{"type":"null"}]},"address_zip":{"oneOf":[{"type":"string"},{"type":"null"}]},"notes":{"oneOf":[{"type":"string"},{"type":"null"}]},"archived_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","tenant_id","name","phone","email","address_line1","address_line2","address_city","address_state","address_zip","notes","archived_at","created_at","updated_at"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"phone":{"type":"string","pattern":"^\\+[1-9][0-9]{1,14}$"},"email":{"oneOf":[{"type":"string","format":"email"},{"type":"null"}]},"address_line1":{"oneOf":[{"type":"string","maxLength":200},{"type":"null"}]},"address_line2":{"oneOf":[{"type":"string","maxLength":200},{"type":"null"}]},"address_city":{"oneOf":[{"type":"string","maxLength":100},{"type":"null"}]},"address_state":{"oneOf":[{"type":"string","maxLength":100},{"type":"null"}]},"address_zip":{"oneOf":[{"type":"string","maxLength":20},{"type":"null"}]},"notes":{"oneOf":[{"type":"string","maxLength":4000},{"type":"null"}]}},"additionalProperties":false}}}}},"delete":{"summary":"Soft-delete a customer. Archived rows persist for historical quote joins.","tags":["customers"],"security":[{"bearerApiKey":["customers:write"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"phone":{"type":"string"},"email":{"oneOf":[{"type":"string"},{"type":"null"}]},"address_line1":{"oneOf":[{"type":"string"},{"type":"null"}]},"address_line2":{"oneOf":[{"type":"string"},{"type":"null"}]},"address_city":{"oneOf":[{"type":"string"},{"type":"null"}]},"address_state":{"oneOf":[{"type":"string"},{"type":"null"}]},"address_zip":{"oneOf":[{"type":"string"},{"type":"null"}]},"notes":{"oneOf":[{"type":"string"},{"type":"null"}]},"archived_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","tenant_id","name","phone","email","address_line1","address_line2","address_city","address_state","address_zip","notes","archived_at","created_at","updated_at"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/services":{"get":{"summary":"List services. Cursor-paginated; search matches name / description / category.","tags":["services"],"security":[{"bearerApiKey":["services:read"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"unit":{"type":"string","enum":["hour","sq_ft","each","linear_ft","flat"]},"unit_price_cents":{"type":"number"},"description":{"oneOf":[{"type":"string"},{"type":"null"}]},"category":{"oneOf":[{"type":"string"},{"type":"null"}]},"archived_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","tenant_id","name","unit","unit_price_cents","description","category","archived_at","created_at","updated_at"],"additionalProperties":false}},"next_cursor":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["data","next_cursor"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"post":{"summary":"Create a service.","tags":["services"],"security":[{"bearerApiKey":["services:write"]}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"unit":{"type":"string","enum":["hour","sq_ft","each","linear_ft","flat"]},"unit_price_cents":{"type":"number"},"description":{"oneOf":[{"type":"string"},{"type":"null"}]},"category":{"oneOf":[{"type":"string"},{"type":"null"}]},"archived_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","tenant_id","name","unit","unit_price_cents","description","category","archived_at","created_at","updated_at"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"unit":{"type":"string","enum":["hour","sq_ft","each","linear_ft","flat"]},"unit_price_cents":{"type":"number"},"description":{"oneOf":[{"type":"string","maxLength":4000},{"type":"null"}]},"category":{"oneOf":[{"type":"string","minLength":1,"maxLength":80},{"type":"null"}]}},"required":["name","unit","unit_price_cents"],"additionalProperties":false}}}}}},"/v1/services/{id}":{"get":{"summary":"Retrieve a single service.","tags":["services"],"security":[{"bearerApiKey":["services:read"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"unit":{"type":"string","enum":["hour","sq_ft","each","linear_ft","flat"]},"unit_price_cents":{"type":"number"},"description":{"oneOf":[{"type":"string"},{"type":"null"}]},"category":{"oneOf":[{"type":"string"},{"type":"null"}]},"archived_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","tenant_id","name","unit","unit_price_cents","description","category","archived_at","created_at","updated_at"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"patch":{"summary":"Partially update a service. Unspecified fields stay unchanged.","tags":["services"],"security":[{"bearerApiKey":["services:write"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"unit":{"type":"string","enum":["hour","sq_ft","each","linear_ft","flat"]},"unit_price_cents":{"type":"number"},"description":{"oneOf":[{"type":"string"},{"type":"null"}]},"category":{"oneOf":[{"type":"string"},{"type":"null"}]},"archived_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","tenant_id","name","unit","unit_price_cents","description","category","archived_at","created_at","updated_at"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"unit":{"type":"string","enum":["hour","sq_ft","each","linear_ft","flat"]},"unit_price_cents":{"type":"number"},"description":{"oneOf":[{"type":"string","maxLength":4000},{"type":"null"}]},"category":{"oneOf":[{"type":"string","minLength":1,"maxLength":80},{"type":"null"}]}},"additionalProperties":false}}}}},"delete":{"summary":"Soft-delete a service. Archived services stay on historical quotes.","tags":["services"],"security":[{"bearerApiKey":["services:write"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"unit":{"type":"string","enum":["hour","sq_ft","each","linear_ft","flat"]},"unit_price_cents":{"type":"number"},"description":{"oneOf":[{"type":"string"},{"type":"null"}]},"category":{"oneOf":[{"type":"string"},{"type":"null"}]},"archived_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","tenant_id","name","unit","unit_price_cents","description","category","archived_at","created_at","updated_at"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/service-bundles":{"get":{"summary":"List service bundles with their items inlined.","tags":["service-bundles"],"security":[{"bearerApiKey":["services:read"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"oneOf":[{"type":"string"},{"type":"null"}]},"archived_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"bundle_id":{"type":"string","format":"uuid"},"service_id":{"type":"string","format":"uuid"},"default_quantity":{"type":"number"},"sort_order":{"type":"number"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","bundle_id","service_id","default_quantity","sort_order","created_at","updated_at"],"additionalProperties":false}}},"required":["id","tenant_id","name","description","archived_at","created_at","updated_at","items"],"additionalProperties":false}},"next_cursor":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["data","next_cursor"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"post":{"summary":"Create a service bundle and its membership list.","tags":["service-bundles"],"security":[{"bearerApiKey":["services:write"]}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"oneOf":[{"type":"string"},{"type":"null"}]},"archived_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"bundle_id":{"type":"string","format":"uuid"},"service_id":{"type":"string","format":"uuid"},"default_quantity":{"type":"number"},"sort_order":{"type":"number"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","bundle_id","service_id","default_quantity","sort_order","created_at","updated_at"],"additionalProperties":false}}},"required":["id","tenant_id","name","description","archived_at","created_at","updated_at","items"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"description":{"oneOf":[{"type":"string","maxLength":4000},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","properties":{"service_id":{"type":"string","format":"uuid"},"default_quantity":{"type":"number"},"sort_order":{"type":"number"}},"required":["service_id","default_quantity"],"additionalProperties":false}}},"required":["name","items"],"additionalProperties":false}}}}}},"/v1/service-bundles/{id}":{"get":{"summary":"Retrieve a single bundle with its items.","tags":["service-bundles"],"security":[{"bearerApiKey":["services:read"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"oneOf":[{"type":"string"},{"type":"null"}]},"archived_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"bundle_id":{"type":"string","format":"uuid"},"service_id":{"type":"string","format":"uuid"},"default_quantity":{"type":"number"},"sort_order":{"type":"number"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","bundle_id","service_id","default_quantity","sort_order","created_at","updated_at"],"additionalProperties":false}}},"required":["id","tenant_id","name","description","archived_at","created_at","updated_at","items"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"patch":{"summary":"Partially update a bundle. `items` absent leaves the list alone; `items: [...]` (or `[]`) atomically replaces the whole list.","tags":["service-bundles"],"security":[{"bearerApiKey":["services:write"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"oneOf":[{"type":"string"},{"type":"null"}]},"archived_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"bundle_id":{"type":"string","format":"uuid"},"service_id":{"type":"string","format":"uuid"},"default_quantity":{"type":"number"},"sort_order":{"type":"number"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","bundle_id","service_id","default_quantity","sort_order","created_at","updated_at"],"additionalProperties":false}}},"required":["id","tenant_id","name","description","archived_at","created_at","updated_at","items"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"description":{"oneOf":[{"type":"string","maxLength":4000},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","properties":{"service_id":{"type":"string","format":"uuid"},"default_quantity":{"type":"number"},"sort_order":{"type":"number"}},"required":["service_id","default_quantity"],"additionalProperties":false}}},"additionalProperties":false}}}}},"delete":{"summary":"Soft-delete a service bundle.","tags":["service-bundles"],"security":[{"bearerApiKey":["services:write"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"oneOf":[{"type":"string"},{"type":"null"}]},"archived_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"bundle_id":{"type":"string","format":"uuid"},"service_id":{"type":"string","format":"uuid"},"default_quantity":{"type":"number"},"sort_order":{"type":"number"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","bundle_id","service_id","default_quantity","sort_order","created_at","updated_at"],"additionalProperties":false}}},"required":["id","tenant_id","name","description","archived_at","created_at","updated_at","items"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/quotes":{"get":{"summary":"List quotes. Filterable by status (CSV), customer_id, expires_before, include_archived; cursor-paginated.","tags":["quotes"],"security":[{"bearerApiKey":["quotes:read"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"customer_id":{"oneOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"quote_number":{"type":"number"},"status":{"type":"string","enum":["draft","sent","viewed","accepted","declined","expired","revision_requested"]},"version":{"type":"number"},"is_multi_tier":{"type":"boolean"},"tier_good_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"tier_better_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"tier_best_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"accepted_tier":{"oneOf":[{"type":"string","enum":["good","better","best"]},{"type":"null"}]},"tax_rate_bps":{"type":"number"},"tax_label":{"oneOf":[{"type":"string"},{"type":"null"}]},"discount_type":{"oneOf":[{"type":"string","enum":["percent","flat"]},{"type":"null"}]},"discount_value":{"oneOf":[{"type":"number"},{"type":"null"}]},"deposit_bps":{"type":"number"},"payment_mode":{"oneOf":[{"type":"string"},{"type":"null"}]},"customer_notes":{"oneOf":[{"type":"string"},{"type":"null"}]},"locale":{"type":"string"},"valid_until":{"oneOf":[{"type":"string"},{"type":"null"}]},"sent_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"share_token":{"oneOf":[{"type":"string"},{"type":"null"}]},"declined_via":{"oneOf":[{"type":"string","enum":["public_link","api"]},{"type":"null"}]},"archived_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"line_items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"quote_id":{"type":"string","format":"uuid"},"service_id":{"oneOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"description":{"type":"string"},"unit":{"type":"string","enum":["hour","sq_ft","each","linear_ft","flat"]},"unit_price_cents":{"type":"number"},"quantity":{"type":"number"},"sort_order":{"type":"number"},"is_taxable":{"type":"boolean"},"tier":{"oneOf":[{"type":"string","enum":["good","better","best"]},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","quote_id","service_id","description","unit","unit_price_cents","quantity","sort_order","is_taxable","tier","created_at","updated_at"],"additionalProperties":false}},"totals":{"type":"object","properties":{"subtotal_cents":{"type":"number"},"discount_cents":{"type":"number"},"taxable_subtotal_cents":{"type":"number"},"tax_cents":{"type":"number"},"total_cents":{"type":"number"},"per_tier_subtotal_cents":{"oneOf":[{"type":"object","properties":{"good":{"type":"number"},"better":{"type":"number"},"best":{"type":"number"}},"required":["good","better","best"],"additionalProperties":false},{"type":"null"}]}},"required":["subtotal_cents","discount_cents","taxable_subtotal_cents","tax_cents","total_cents","per_tier_subtotal_cents"],"additionalProperties":false}},"required":["id","tenant_id","customer_id","quote_number","status","version","is_multi_tier","tier_good_name","tier_better_name","tier_best_name","accepted_tier","tax_rate_bps","tax_label","discount_type","discount_value","deposit_bps","payment_mode","customer_notes","locale","valid_until","sent_at","share_token","declined_via","archived_at","created_at","updated_at","line_items","totals"],"additionalProperties":false}},"next_cursor":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["data","next_cursor"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"post":{"summary":"Create a draft quote with line items inline.","tags":["quotes"],"security":[{"bearerApiKey":["quotes:write"]}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"customer_id":{"oneOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"quote_number":{"type":"number"},"status":{"type":"string","enum":["draft","sent","viewed","accepted","declined","expired","revision_requested"]},"version":{"type":"number"},"is_multi_tier":{"type":"boolean"},"tier_good_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"tier_better_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"tier_best_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"accepted_tier":{"oneOf":[{"type":"string","enum":["good","better","best"]},{"type":"null"}]},"tax_rate_bps":{"type":"number"},"tax_label":{"oneOf":[{"type":"string"},{"type":"null"}]},"discount_type":{"oneOf":[{"type":"string","enum":["percent","flat"]},{"type":"null"}]},"discount_value":{"oneOf":[{"type":"number"},{"type":"null"}]},"deposit_bps":{"type":"number"},"payment_mode":{"oneOf":[{"type":"string"},{"type":"null"}]},"customer_notes":{"oneOf":[{"type":"string"},{"type":"null"}]},"locale":{"type":"string"},"valid_until":{"oneOf":[{"type":"string"},{"type":"null"}]},"sent_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"share_token":{"oneOf":[{"type":"string"},{"type":"null"}]},"declined_via":{"oneOf":[{"type":"string","enum":["public_link","api"]},{"type":"null"}]},"archived_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"line_items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"quote_id":{"type":"string","format":"uuid"},"service_id":{"oneOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"description":{"type":"string"},"unit":{"type":"string","enum":["hour","sq_ft","each","linear_ft","flat"]},"unit_price_cents":{"type":"number"},"quantity":{"type":"number"},"sort_order":{"type":"number"},"is_taxable":{"type":"boolean"},"tier":{"oneOf":[{"type":"string","enum":["good","better","best"]},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","quote_id","service_id","description","unit","unit_price_cents","quantity","sort_order","is_taxable","tier","created_at","updated_at"],"additionalProperties":false}},"totals":{"type":"object","properties":{"subtotal_cents":{"type":"number"},"discount_cents":{"type":"number"},"taxable_subtotal_cents":{"type":"number"},"tax_cents":{"type":"number"},"total_cents":{"type":"number"},"per_tier_subtotal_cents":{"oneOf":[{"type":"object","properties":{"good":{"type":"number"},"better":{"type":"number"},"best":{"type":"number"}},"required":["good","better","best"],"additionalProperties":false},{"type":"null"}]}},"required":["subtotal_cents","discount_cents","taxable_subtotal_cents","tax_cents","total_cents","per_tier_subtotal_cents"],"additionalProperties":false}},"required":["id","tenant_id","customer_id","quote_number","status","version","is_multi_tier","tier_good_name","tier_better_name","tier_best_name","accepted_tier","tax_rate_bps","tax_label","discount_type","discount_value","deposit_bps","payment_mode","customer_notes","locale","valid_until","sent_at","share_token","declined_via","archived_at","created_at","updated_at","line_items","totals"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"customer_id":{"oneOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"valid_until":{"oneOf":[{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},{"type":"null"}]},"tax_rate_bps":{"type":"number"},"tax_label":{"oneOf":[{"type":"string","maxLength":40},{"type":"null"}]},"discount_type":{"oneOf":[{"type":"string","enum":["percent","flat"]},{"type":"null"}]},"discount_value":{"oneOf":[{"type":"number"},{"type":"null"}]},"deposit_bps":{"type":"number"},"payment_mode":{"oneOf":[{"type":"string","maxLength":60},{"type":"null"}]},"customer_notes":{"oneOf":[{"type":"string","maxLength":4000},{"type":"null"}]},"line_items":{"type":"array","items":{"type":"object","properties":{"service_id":{"oneOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"description":{"type":"string","minLength":1,"maxLength":2000},"unit":{"type":"string","enum":["hour","sq_ft","each","linear_ft","flat"]},"unit_price_cents":{"type":"number"},"quantity":{"type":"number"},"is_taxable":{"type":"boolean"},"tier":{"oneOf":[{"type":"string","enum":["good","better","best"]},{"type":"null"}]},"sort_order":{"type":"number"}},"required":["description","unit","unit_price_cents","quantity"],"additionalProperties":false}}},"additionalProperties":false}}}}}},"/v1/quotes/{id}":{"get":{"summary":"Retrieve a single quote with its line items + totals.","tags":["quotes"],"security":[{"bearerApiKey":["quotes:read"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"customer_id":{"oneOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"quote_number":{"type":"number"},"status":{"type":"string","enum":["draft","sent","viewed","accepted","declined","expired","revision_requested"]},"version":{"type":"number"},"is_multi_tier":{"type":"boolean"},"tier_good_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"tier_better_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"tier_best_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"accepted_tier":{"oneOf":[{"type":"string","enum":["good","better","best"]},{"type":"null"}]},"tax_rate_bps":{"type":"number"},"tax_label":{"oneOf":[{"type":"string"},{"type":"null"}]},"discount_type":{"oneOf":[{"type":"string","enum":["percent","flat"]},{"type":"null"}]},"discount_value":{"oneOf":[{"type":"number"},{"type":"null"}]},"deposit_bps":{"type":"number"},"payment_mode":{"oneOf":[{"type":"string"},{"type":"null"}]},"customer_notes":{"oneOf":[{"type":"string"},{"type":"null"}]},"locale":{"type":"string"},"valid_until":{"oneOf":[{"type":"string"},{"type":"null"}]},"sent_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"share_token":{"oneOf":[{"type":"string"},{"type":"null"}]},"declined_via":{"oneOf":[{"type":"string","enum":["public_link","api"]},{"type":"null"}]},"archived_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"line_items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"quote_id":{"type":"string","format":"uuid"},"service_id":{"oneOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"description":{"type":"string"},"unit":{"type":"string","enum":["hour","sq_ft","each","linear_ft","flat"]},"unit_price_cents":{"type":"number"},"quantity":{"type":"number"},"sort_order":{"type":"number"},"is_taxable":{"type":"boolean"},"tier":{"oneOf":[{"type":"string","enum":["good","better","best"]},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","quote_id","service_id","description","unit","unit_price_cents","quantity","sort_order","is_taxable","tier","created_at","updated_at"],"additionalProperties":false}},"totals":{"type":"object","properties":{"subtotal_cents":{"type":"number"},"discount_cents":{"type":"number"},"taxable_subtotal_cents":{"type":"number"},"tax_cents":{"type":"number"},"total_cents":{"type":"number"},"per_tier_subtotal_cents":{"oneOf":[{"type":"object","properties":{"good":{"type":"number"},"better":{"type":"number"},"best":{"type":"number"}},"required":["good","better","best"],"additionalProperties":false},{"type":"null"}]}},"required":["subtotal_cents","discount_cents","taxable_subtotal_cents","tax_cents","total_cents","per_tier_subtotal_cents"],"additionalProperties":false}},"required":["id","tenant_id","customer_id","quote_number","status","version","is_multi_tier","tier_good_name","tier_better_name","tier_best_name","accepted_tier","tax_rate_bps","tax_label","discount_type","discount_value","deposit_bps","payment_mode","customer_notes","locale","valid_until","sent_at","share_token","declined_via","archived_at","created_at","updated_at","line_items","totals"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"patch":{"summary":"Partially update a draft quote.  Non-draft → 409 invalid-state-transition. `line_items` absent leaves the list alone; `line_items: [...]` (or `[]`) atomically replaces the whole list.","tags":["quotes"],"security":[{"bearerApiKey":["quotes:write"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"customer_id":{"oneOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"quote_number":{"type":"number"},"status":{"type":"string","enum":["draft","sent","viewed","accepted","declined","expired","revision_requested"]},"version":{"type":"number"},"is_multi_tier":{"type":"boolean"},"tier_good_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"tier_better_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"tier_best_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"accepted_tier":{"oneOf":[{"type":"string","enum":["good","better","best"]},{"type":"null"}]},"tax_rate_bps":{"type":"number"},"tax_label":{"oneOf":[{"type":"string"},{"type":"null"}]},"discount_type":{"oneOf":[{"type":"string","enum":["percent","flat"]},{"type":"null"}]},"discount_value":{"oneOf":[{"type":"number"},{"type":"null"}]},"deposit_bps":{"type":"number"},"payment_mode":{"oneOf":[{"type":"string"},{"type":"null"}]},"customer_notes":{"oneOf":[{"type":"string"},{"type":"null"}]},"locale":{"type":"string"},"valid_until":{"oneOf":[{"type":"string"},{"type":"null"}]},"sent_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"share_token":{"oneOf":[{"type":"string"},{"type":"null"}]},"declined_via":{"oneOf":[{"type":"string","enum":["public_link","api"]},{"type":"null"}]},"archived_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"line_items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"quote_id":{"type":"string","format":"uuid"},"service_id":{"oneOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"description":{"type":"string"},"unit":{"type":"string","enum":["hour","sq_ft","each","linear_ft","flat"]},"unit_price_cents":{"type":"number"},"quantity":{"type":"number"},"sort_order":{"type":"number"},"is_taxable":{"type":"boolean"},"tier":{"oneOf":[{"type":"string","enum":["good","better","best"]},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","quote_id","service_id","description","unit","unit_price_cents","quantity","sort_order","is_taxable","tier","created_at","updated_at"],"additionalProperties":false}},"totals":{"type":"object","properties":{"subtotal_cents":{"type":"number"},"discount_cents":{"type":"number"},"taxable_subtotal_cents":{"type":"number"},"tax_cents":{"type":"number"},"total_cents":{"type":"number"},"per_tier_subtotal_cents":{"oneOf":[{"type":"object","properties":{"good":{"type":"number"},"better":{"type":"number"},"best":{"type":"number"}},"required":["good","better","best"],"additionalProperties":false},{"type":"null"}]}},"required":["subtotal_cents","discount_cents","taxable_subtotal_cents","tax_cents","total_cents","per_tier_subtotal_cents"],"additionalProperties":false}},"required":["id","tenant_id","customer_id","quote_number","status","version","is_multi_tier","tier_good_name","tier_better_name","tier_best_name","accepted_tier","tax_rate_bps","tax_label","discount_type","discount_value","deposit_bps","payment_mode","customer_notes","locale","valid_until","sent_at","share_token","declined_via","archived_at","created_at","updated_at","line_items","totals"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"customer_id":{"oneOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"valid_until":{"oneOf":[{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},{"type":"null"}]},"tax_rate_bps":{"type":"number"},"tax_label":{"oneOf":[{"type":"string","maxLength":40},{"type":"null"}]},"discount_type":{"oneOf":[{"type":"string","enum":["percent","flat"]},{"type":"null"}]},"discount_value":{"oneOf":[{"type":"number"},{"type":"null"}]},"deposit_bps":{"type":"number"},"payment_mode":{"oneOf":[{"type":"string","maxLength":60},{"type":"null"}]},"customer_notes":{"oneOf":[{"type":"string","maxLength":4000},{"type":"null"}]},"line_items":{"type":"array","items":{"type":"object","properties":{"service_id":{"oneOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"description":{"type":"string","minLength":1,"maxLength":2000},"unit":{"type":"string","enum":["hour","sq_ft","each","linear_ft","flat"]},"unit_price_cents":{"type":"number"},"quantity":{"type":"number"},"is_taxable":{"type":"boolean"},"tier":{"oneOf":[{"type":"string","enum":["good","better","best"]},{"type":"null"}]},"sort_order":{"type":"number"}},"required":["description","unit","unit_price_cents","quantity"],"additionalProperties":false}}},"additionalProperties":false}}}}}},"/v1/quotes/{id}/send":{"post":{"summary":"Send a draft quote.  Mints a share_token, snapshots the locale, and emits the quote.sent event.  Per-channel email/sms toggles in the body; defaults to both enabled.","tags":["quotes"],"security":[{"bearerApiKey":["quotes:write"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"customer_id":{"oneOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"quote_number":{"type":"number"},"status":{"type":"string","enum":["draft","sent","viewed","accepted","declined","expired","revision_requested"]},"version":{"type":"number"},"is_multi_tier":{"type":"boolean"},"tier_good_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"tier_better_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"tier_best_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"accepted_tier":{"oneOf":[{"type":"string","enum":["good","better","best"]},{"type":"null"}]},"tax_rate_bps":{"type":"number"},"tax_label":{"oneOf":[{"type":"string"},{"type":"null"}]},"discount_type":{"oneOf":[{"type":"string","enum":["percent","flat"]},{"type":"null"}]},"discount_value":{"oneOf":[{"type":"number"},{"type":"null"}]},"deposit_bps":{"type":"number"},"payment_mode":{"oneOf":[{"type":"string"},{"type":"null"}]},"customer_notes":{"oneOf":[{"type":"string"},{"type":"null"}]},"locale":{"type":"string"},"valid_until":{"oneOf":[{"type":"string"},{"type":"null"}]},"sent_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"share_token":{"oneOf":[{"type":"string"},{"type":"null"}]},"declined_via":{"oneOf":[{"type":"string","enum":["public_link","api"]},{"type":"null"}]},"archived_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"line_items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"quote_id":{"type":"string","format":"uuid"},"service_id":{"oneOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"description":{"type":"string"},"unit":{"type":"string","enum":["hour","sq_ft","each","linear_ft","flat"]},"unit_price_cents":{"type":"number"},"quantity":{"type":"number"},"sort_order":{"type":"number"},"is_taxable":{"type":"boolean"},"tier":{"oneOf":[{"type":"string","enum":["good","better","best"]},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","quote_id","service_id","description","unit","unit_price_cents","quantity","sort_order","is_taxable","tier","created_at","updated_at"],"additionalProperties":false}},"totals":{"type":"object","properties":{"subtotal_cents":{"type":"number"},"discount_cents":{"type":"number"},"taxable_subtotal_cents":{"type":"number"},"tax_cents":{"type":"number"},"total_cents":{"type":"number"},"per_tier_subtotal_cents":{"oneOf":[{"type":"object","properties":{"good":{"type":"number"},"better":{"type":"number"},"best":{"type":"number"}},"required":["good","better","best"],"additionalProperties":false},{"type":"null"}]}},"required":["subtotal_cents","discount_cents","taxable_subtotal_cents","tax_cents","total_cents","per_tier_subtotal_cents"],"additionalProperties":false}},"required":["id","tenant_id","customer_id","quote_number","status","version","is_multi_tier","tier_good_name","tier_better_name","tier_best_name","accepted_tier","tax_rate_bps","tax_label","discount_type","discount_value","deposit_bps","payment_mode","customer_notes","locale","valid_until","sent_at","share_token","declined_via","archived_at","created_at","updated_at","line_items","totals"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"valid_until":{"oneOf":[{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},{"type":"null"}]},"locale_override":{"oneOf":[{"type":"string","minLength":2,"maxLength":20},{"type":"null"}]},"channels":{"type":"object","properties":{"email":{"type":"boolean"},"sms":{"type":"boolean"}},"additionalProperties":false}},"additionalProperties":false}}}}}},"/v1/quotes/{id}/accept":{"post":{"summary":"Accept a sent (or viewed) quote on behalf of the customer.  Records signature_name + terms_version on the legal signature row with capture_method=api and accepted_via_api_key_id pointing at the calling key.","tags":["quotes"],"security":[{"bearerApiKey":["quotes:write"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"customer_id":{"oneOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"quote_number":{"type":"number"},"status":{"type":"string","enum":["draft","sent","viewed","accepted","declined","expired","revision_requested"]},"version":{"type":"number"},"is_multi_tier":{"type":"boolean"},"tier_good_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"tier_better_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"tier_best_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"accepted_tier":{"oneOf":[{"type":"string","enum":["good","better","best"]},{"type":"null"}]},"tax_rate_bps":{"type":"number"},"tax_label":{"oneOf":[{"type":"string"},{"type":"null"}]},"discount_type":{"oneOf":[{"type":"string","enum":["percent","flat"]},{"type":"null"}]},"discount_value":{"oneOf":[{"type":"number"},{"type":"null"}]},"deposit_bps":{"type":"number"},"payment_mode":{"oneOf":[{"type":"string"},{"type":"null"}]},"customer_notes":{"oneOf":[{"type":"string"},{"type":"null"}]},"locale":{"type":"string"},"valid_until":{"oneOf":[{"type":"string"},{"type":"null"}]},"sent_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"share_token":{"oneOf":[{"type":"string"},{"type":"null"}]},"declined_via":{"oneOf":[{"type":"string","enum":["public_link","api"]},{"type":"null"}]},"archived_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"line_items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"quote_id":{"type":"string","format":"uuid"},"service_id":{"oneOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"description":{"type":"string"},"unit":{"type":"string","enum":["hour","sq_ft","each","linear_ft","flat"]},"unit_price_cents":{"type":"number"},"quantity":{"type":"number"},"sort_order":{"type":"number"},"is_taxable":{"type":"boolean"},"tier":{"oneOf":[{"type":"string","enum":["good","better","best"]},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","quote_id","service_id","description","unit","unit_price_cents","quantity","sort_order","is_taxable","tier","created_at","updated_at"],"additionalProperties":false}},"totals":{"type":"object","properties":{"subtotal_cents":{"type":"number"},"discount_cents":{"type":"number"},"taxable_subtotal_cents":{"type":"number"},"tax_cents":{"type":"number"},"total_cents":{"type":"number"},"per_tier_subtotal_cents":{"oneOf":[{"type":"object","properties":{"good":{"type":"number"},"better":{"type":"number"},"best":{"type":"number"}},"required":["good","better","best"],"additionalProperties":false},{"type":"null"}]}},"required":["subtotal_cents","discount_cents","taxable_subtotal_cents","tax_cents","total_cents","per_tier_subtotal_cents"],"additionalProperties":false}},"required":["id","tenant_id","customer_id","quote_number","status","version","is_multi_tier","tier_good_name","tier_better_name","tier_best_name","accepted_tier","tax_rate_bps","tax_label","discount_type","discount_value","deposit_bps","payment_mode","customer_notes","locale","valid_until","sent_at","share_token","declined_via","archived_at","created_at","updated_at","line_items","totals"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"signature_name":{"type":"string","minLength":1,"maxLength":200},"terms_version":{"type":"string","minLength":1,"maxLength":60},"signature_data_b64":{"oneOf":[{"type":"string"},{"type":"null"}]},"accepted_tier":{"oneOf":[{"type":"string","enum":["good","better","best"]},{"type":"null"}]}},"required":["signature_name","terms_version"],"additionalProperties":false}}}}}},"/v1/quotes/{id}/decline":{"post":{"summary":"Decline a sent (or viewed) quote on behalf of the customer.  Stamps declined_via=api and declined_via_api_key_id on the quote.","tags":["quotes"],"security":[{"bearerApiKey":["quotes:write"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"customer_id":{"oneOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"quote_number":{"type":"number"},"status":{"type":"string","enum":["draft","sent","viewed","accepted","declined","expired","revision_requested"]},"version":{"type":"number"},"is_multi_tier":{"type":"boolean"},"tier_good_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"tier_better_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"tier_best_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"accepted_tier":{"oneOf":[{"type":"string","enum":["good","better","best"]},{"type":"null"}]},"tax_rate_bps":{"type":"number"},"tax_label":{"oneOf":[{"type":"string"},{"type":"null"}]},"discount_type":{"oneOf":[{"type":"string","enum":["percent","flat"]},{"type":"null"}]},"discount_value":{"oneOf":[{"type":"number"},{"type":"null"}]},"deposit_bps":{"type":"number"},"payment_mode":{"oneOf":[{"type":"string"},{"type":"null"}]},"customer_notes":{"oneOf":[{"type":"string"},{"type":"null"}]},"locale":{"type":"string"},"valid_until":{"oneOf":[{"type":"string"},{"type":"null"}]},"sent_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"share_token":{"oneOf":[{"type":"string"},{"type":"null"}]},"declined_via":{"oneOf":[{"type":"string","enum":["public_link","api"]},{"type":"null"}]},"archived_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"line_items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"quote_id":{"type":"string","format":"uuid"},"service_id":{"oneOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"description":{"type":"string"},"unit":{"type":"string","enum":["hour","sq_ft","each","linear_ft","flat"]},"unit_price_cents":{"type":"number"},"quantity":{"type":"number"},"sort_order":{"type":"number"},"is_taxable":{"type":"boolean"},"tier":{"oneOf":[{"type":"string","enum":["good","better","best"]},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","quote_id","service_id","description","unit","unit_price_cents","quantity","sort_order","is_taxable","tier","created_at","updated_at"],"additionalProperties":false}},"totals":{"type":"object","properties":{"subtotal_cents":{"type":"number"},"discount_cents":{"type":"number"},"taxable_subtotal_cents":{"type":"number"},"tax_cents":{"type":"number"},"total_cents":{"type":"number"},"per_tier_subtotal_cents":{"oneOf":[{"type":"object","properties":{"good":{"type":"number"},"better":{"type":"number"},"best":{"type":"number"}},"required":["good","better","best"],"additionalProperties":false},{"type":"null"}]}},"required":["subtotal_cents","discount_cents","taxable_subtotal_cents","tax_cents","total_cents","per_tier_subtotal_cents"],"additionalProperties":false}},"required":["id","tenant_id","customer_id","quote_number","status","version","is_multi_tier","tier_good_name","tier_better_name","tier_best_name","accepted_tier","tax_rate_bps","tax_label","discount_type","discount_value","deposit_bps","payment_mode","customer_notes","locale","valid_until","sent_at","share_token","declined_via","archived_at","created_at","updated_at","line_items","totals"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"oneOf":[{"type":"string","maxLength":2000},{"type":"null"}]}},"additionalProperties":false}}}}}},"/v1/account":{"get":{"summary":"Retrieve the calling tenant's account info.","tags":["account"],"security":[{"bearerApiKey":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"brand_display_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"brand_primary_hex":{"oneOf":[{"type":"string"},{"type":"null"}]},"brand_secondary_hex":{"oneOf":[{"type":"string"},{"type":"null"}]},"logo_url":{"oneOf":[{"type":"string"},{"type":"null"}]},"phone":{"oneOf":[{"type":"string"},{"type":"null"}]},"service_area":{"oneOf":[{"type":"string"},{"type":"null"}]},"locale":{"type":"string"},"plan_tier":{"type":"string"},"default_tax_rate_bps":{"type":"number"},"default_deposit_bps":{"type":"number"},"onboarded_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","brand_display_name","brand_primary_hex","brand_secondary_hex","logo_url","phone","service_area","locale","plan_tier","default_tax_rate_bps","default_deposit_bps","onboarded_at","created_at","updated_at"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/webhooks":{"get":{"summary":"List webhook subscriptions for the calling tenant. Cursor-paginated.","tags":["webhooks"],"security":[{"bearerApiKey":["webhooks:manage"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"url":{"type":"string"},"description":{"oneOf":[{"type":"string"},{"type":"null"}]},"event_types":{"type":"array","items":{"type":"string"}},"disabled":{"type":"boolean"},"disabled_reason":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","tenant_id","url","description","event_types","disabled","disabled_reason","created_at","updated_at"],"additionalProperties":false}},"next_cursor":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["data","next_cursor"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"post":{"summary":"Create a webhook subscription. The signing secret is returned ONCE in the response body — store it before dismissing the call. Capped at 10 subscriptions per tenant (409 on overflow).","tags":["webhooks"],"security":[{"bearerApiKey":["webhooks:manage"]}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"url":{"type":"string"},"description":{"oneOf":[{"type":"string"},{"type":"null"}]},"event_types":{"type":"array","items":{"type":"string"}},"disabled":{"type":"boolean"},"disabled_reason":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"secret":{"type":"string"}},"required":["id","tenant_id","url","description","event_types","disabled","disabled_reason","created_at","updated_at","secret"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","pattern":"^https:\\/\\/[^\\s]+$"},"description":{"oneOf":[{"type":"string","maxLength":200},{"type":"null"}]},"event_types":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100}}},"required":["url"],"additionalProperties":false}}}}}},"/v1/webhooks/{id}":{"get":{"summary":"Retrieve a single webhook subscription. Secret is never returned here.","tags":["webhooks"],"security":[{"bearerApiKey":["webhooks:manage"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"url":{"type":"string"},"description":{"oneOf":[{"type":"string"},{"type":"null"}]},"event_types":{"type":"array","items":{"type":"string"}},"disabled":{"type":"boolean"},"disabled_reason":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","tenant_id","url","description","event_types","disabled","disabled_reason","created_at","updated_at"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"patch":{"summary":"Partially update a webhook subscription. `disabled: true` pauses delivery (without deleting); `disabled: false` resumes. Unspecified fields stay unchanged.","tags":["webhooks"],"security":[{"bearerApiKey":["webhooks:manage"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"url":{"type":"string"},"description":{"oneOf":[{"type":"string"},{"type":"null"}]},"event_types":{"type":"array","items":{"type":"string"}},"disabled":{"type":"boolean"},"disabled_reason":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","tenant_id","url","description","event_types","disabled","disabled_reason","created_at","updated_at"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","pattern":"^https:\\/\\/[^\\s]+$"},"description":{"oneOf":[{"type":"string","maxLength":200},{"type":"null"}]},"event_types":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100}},"disabled":{"type":"boolean"}},"additionalProperties":false}}}}},"delete":{"summary":"Hard-delete a webhook subscription and its signing secret. Idempotent (404 once gone).","tags":["webhooks"],"security":[{"bearerApiKey":["webhooks:manage"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"deleted":{"const":true}},"required":["id","deleted"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/v1/webhooks/{id}/rotate-secret":{"post":{"summary":"Mint a fresh signing secret for an existing subscription. The old secret is invalidated immediately — receivers must swap atomically. Returns the new secret ONCE.","tags":["webhooks"],"security":[{"bearerApiKey":["webhooks:manage"]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenant_id":{"type":"string","format":"uuid"},"url":{"type":"string"},"description":{"oneOf":[{"type":"string"},{"type":"null"}]},"event_types":{"type":"array","items":{"type":"string"}},"disabled":{"type":"boolean"},"disabled_reason":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"secret":{"type":"string"}},"required":["id","tenant_id","url","description","event_types","disabled","disabled_reason","created_at","updated_at","secret"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":false}}}}}},"/v1/webhook-events":{"get":{"summary":"List the event types tenants can subscribe to via /v1/webhooks. Auth-only (no scope) — same gate as /v1/account.","tags":["webhooks"],"security":[{"bearerApiKey":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"event_type":{"type":"string"},"description":{"type":"string"},"since_version":{"type":"string"},"resource":{"type":"string","enum":["quotes","deposits","customers","services","bundles"]}},"required":["event_type","description","since_version","resource"],"additionalProperties":false}}},"required":["data"],"additionalProperties":false}}}},"401":{"description":"Invalid or revoked API key","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}}},"components":{"securitySchemes":{"bearerApiKey":{"type":"http","scheme":"bearer","bearerFormat":"kit_<env>_<public_id>_<secret>","description":"Kitorium API key, issued from tenant Settings → Developer. Format: `kit_<live|test>_<12-char public_id>_<32-char secret>`. See ADR-004 + ADR-012."}},"schemas":{"Problem":{"type":"object","properties":{"type":{"type":"string"},"title":{"type":"string"},"status":{"type":"number"},"detail":{"type":"string"},"instance":{"type":"string"}},"required":["type","title","status"],"additionalProperties":false}}}}