{"openapi":"3.1.0","info":{"title":"Dashly API","version":"v1","description":"Dashly's public API. The promise it is built around: **anything the dashboard can do, a key\ncan do too.**\n\nIt is not written endpoint by endpoint — it is **generated from a catalog of resources**.\nThat is what makes every collection behave the same way: the same pagination, the same\nfilter grammar, the same error shape, the same handling of your agency's custom fields.\nLearn one resource and you have learned all 48.\n\n### Get your first response in two minutes\n\n1. Create a key in **Settings → Integrations**. The secret is shown **once** — only its\n   SHA-256 hash\n   is stored, so a lost key is replaced, never recovered.\n2. Call `GET /me`. It validates the key and tells you what it may do, without touching any\n   data. Paste your key into the **Test Request** panel on any operation below to try it.\n3. Call `GET /` for the catalog: every resource, its readable fields, its writable fields,\n   its filters, its sorts.\n4. Call `GET /fields` for the field registry — the built-in fields plus the custom fields\n   *your* agency configured. The `customFields` bag cannot be guessed; this is where its\n   keys come from.\n\n### What to know before you write code\n\n- **A key authenticates an agency, not a person.** Every read and write is bounded to that\n  agency by row-level security in Postgres. The person who issued the key is the author\n  recorded in the audit log, and every API write is marked `via: \"api\"` — or with the\n  surface that made it, when the client names one in `X-Dashly-Surface` (the MCP server\n  sends `mcp`, so an agency can tell an agent's writes from an integration's). The header\n  grants nothing; it only colours the audit trail. A name of your own (`[a-z0-9_-]{1,20}`)\n  is stored prefixed, as `api:<name>`; the words the product uses for its own surfaces\n  are ignored and fall back to `api`.\n- **An API id is always a public id** (`hsbftmp3f5`, `fld_…`), never an internal UUID —\n  in relations too. Passing a UUID returns `404`.\n- **Branch on `error.code`, never on the message.** Messages are free to change; the codes\n  are part of the contract.\n- **Two limits, both answering `429`.** 120 requests per minute per key bounds how *fast*\n  you may call; a monthly token allowance bounds how *much*. `details.reason` tells them\n  apart and `Retry-After` says how long to wait. The `X-RateLimit-*` and `X-Quota-*`\n  headers ride on every response, not only on refusals, so you can back off before you are\n  refused.\n- **Unknown filters and sorts are errors, not silence.** A `filter[…]` or `sort` a resource\n  does not declare returns `400` with the list of what it does accept.\n\n### Known limits of v1\n\nOffset pagination, no cursor — it drifts on a collection that changes while you read it ·\n`PATCH` **replaces** the `customFields` bag instead of merging it: read the record, merge,\nthen write · no idempotency on `POST` — a replay creates a duplicate · no webhooks wired to\nAPI writes yet.","contact":{"name":"Dashly support","email":"contact@usedashly.com"},"termsOfService":"https://www.usedashly.com/terms","license":{"name":"Proprietary — governed by the terms of service","url":"https://www.usedashly.com/terms"}},"servers":[{"url":"https://api.usedashly.com/v1"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Getting started","description":"Discovery, key introspection, the field registry, and this document."},{"name":"Clients","description":"`/clients`"},{"name":"Contacts","description":"`/contacts`"},{"name":"Deals","description":"`/deals`"},{"name":"Leads","description":"`/leads`"},{"name":"Projects","description":"`/projects`"},{"name":"Tickets","description":"`/tickets`"},{"name":"Time logs","description":"`/time-logs`"},{"name":"Workflow columns","description":"`/workflow-statuses` — read-only"},{"name":"Retainers","description":"`/forfaits`"},{"name":"Docs","description":"`/docs`"},{"name":"Categories","description":"`/categories` — read-only"},{"name":"Teams","description":"`/teams` — read-only"},{"name":"Pipelines","description":"`/pipelines`"},{"name":"Pipeline stages","description":"`/pipeline-stages` — read-only"},{"name":"Members","description":"`/members` — read-only"},{"name":"Custom fields","description":"`/field-definitions`"},{"name":"Comments","description":"`/comments`"},{"name":"Activities","description":"`/activities`"},{"name":"Proposals","description":"`/proposals`"},{"name":"Reports","description":"`/reports`"},{"name":"Report templates","description":"`/report-templates` — read-only"},{"name":"Report schedules","description":"`/report-schedules` — read-only"},{"name":"Chat channels","description":"`/chat-channels`"},{"name":"Chat messages","description":"`/chat-messages`"},{"name":"Decks","description":"`/decks`"},{"name":"Deck comments","description":"`/deck-comments` — read-only"},{"name":"Portal invitations","description":"`/portal-invitations`"},{"name":"Connectors","description":"`/connector-connections`"},{"name":"Agency settings","description":"`/agency-settings` — read-only"},{"name":"Portal branding","description":"`/branding` — read-only"},{"name":"Doc folders","description":"`/doc-folders`"},{"name":"Lost reasons","description":"`/lost-reasons`"},{"name":"Lead sources","description":"`/lead-sources`"},{"name":"Contact roles","description":"`/contact-roles`"},{"name":"Tax rates","description":"`/tax-rates`"},{"name":"Deal products","description":"`/deal-products` — read-only"},{"name":"Products","description":"`/products`"},{"name":"Product categories","description":"`/product-categories`"},{"name":"Product packages","description":"`/product-packages`"},{"name":"Ticket templates","description":"`/ticket-templates`"},{"name":"Recurring tickets","description":"`/recurring-tickets`"},{"name":"Project templates","description":"`/project-templates`"},{"name":"Ticket automations","description":"`/ticket-automations` — read-only"},{"name":"Automation tags","description":"`/automation-tags` — read-only"},{"name":"Project types","description":"`/project-types`"},{"name":"Onboarding template steps","description":"`/onboarding-template-steps` — read-only"},{"name":"Billing documents","description":"`/billing-documents` — read-only"},{"name":"Domains","description":"`/domains` — read-only"},{"name":"Blog posts","description":"`/blog-posts` — read-only"},{"name":"Partners","description":"`/partners`"},{"name":"Deal partners","description":"`/deal-partners`"},{"name":"Suggestions","description":"`/suggestions` — read-only"},{"name":"AI visibility settings","description":"`/geo-settings`"},{"name":"AI visibility prompts","description":"`/geo-prompts`"},{"name":"Review remarks","description":"`/review-remarks` — read-only"},{"name":"Review sites","description":"`/review-sites` — read-only"}],"paths":{"/":{"get":{"operationId":"getIndex","tags":["Getting started"],"summary":"Discover every resource","description":"The live catalog: every collection, the fields it returns, the fields you may write, what can be filtered, sorted and searched, and the scopes each one needs. An integration can be built from this response plus `/fields` without reading a line of prose.\n\n**Required scope:** `any valid key`.","responses":{"200":{"description":"The catalog.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"version":{"type":"string"},"resources":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"path":{"type":"string"},"methods":{"type":"array","items":{"type":"string"}},"attributes":{"type":"array","items":{"type":"string"}},"writable":{"type":"array","items":{"type":"string"}},"relations":{"type":"array","items":{"type":"string"}},"filterable":{"type":"array","items":{"type":"string"}},"actions":{"type":"array","items":{"type":"string"}},"sortable":{"type":"array","items":{"type":"string"}},"searchable":{"type":"array","items":{"type":"string"}},"customFields":{"type":["string","null"]},"scopes":{"type":"array","items":{"type":"string"}}}}}},"required":["version","resources"]}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/me":{"get":{"operationId":"getMe","tags":["Getting started"],"summary":"Check your key","description":"**Start here.** It validates the key, names the agency it belongs to and lists its scopes, without touching any data. The token allowance is in the body as well as in the headers, because this is the call a client library makes at startup — and one that had to issue a throwaway request just to read a header would issue one.\n\n**Required scope:** `any valid key`.","responses":{"200":{"description":"The agency, the scopes, the allowance.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"agency":{"type":"object","properties":{"name":{"type":["string","null"]},"slug":{"type":["string","null"]}}},"scopes":{"type":"array","items":{"type":"string"}},"quota":{"type":"object","properties":{"used":{"type":"integer"},"limit":{"type":["integer","null"]},"remaining":{"type":["integer","null"]},"unlimited":{"type":"boolean"},"resetsAt":{"type":"string"}}}},"required":["agency","scopes","quota"]}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/fields":{"get":{"operationId":"getFields","tags":["Getting started"],"summary":"Read the field registry","description":"What makes the rest usable. Every agency configures its own fields on clients, deals, leads and tickets; an integration cannot guess them, so it reads them. For each entity you get the built-in fields **and** this agency's custom ones in one list, with the key to use, the type it holds, whether it is required, and the choices a `select` accepts.\n\n**Required scope:** `any valid key`.","parameters":[{"name":"entity","in":"query","description":"Narrow to one entity. Omit it for all four.","schema":{"type":"string","enum":["ticket","deal","account","lead","contact"]}}],"responses":{"200":{"description":"The registry, keyed by entity.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"`<entity>.<key>` for a built-in field, `fld_…` for a custom one."},"key":{"type":"string"},"label":{"type":"string"},"type":{"type":"string"},"required":{"type":"boolean"},"source":{"type":"string","enum":["builtin","custom"]},"deletable":{"type":"boolean"},"options":{"type":"array","items":{"type":"object"}},"location":{"type":"string","enum":["attribute","customFields"],"description":"Where the value lives on the record: a top-level attribute for a built-in field, an entry of the `customFields` bag for a custom one."}}}}}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/openapi.json":{"get":{"operationId":"getOpenApiDocument","tags":["Getting started"],"summary":"Fetch this document","description":"The OpenAPI 3.1 description of this API, generated from the catalog on every call — so it cannot drift from what the API actually does. Point Postman, Insomnia, Bruno or an SDK generator straight at this URL.\n\n**The one route that needs no key**, and the one response with no `data` envelope: a tool reading a spec expects the document at the root.\n\n**No key required.**","security":[],"responses":{"200":{"description":"The OpenAPI document, at the root of the body.","content":{"application/json":{"schema":{"type":"object","description":"An OpenAPI 3.1 document."}}}},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients":{"get":{"operationId":"listClients","tags":["Clients"],"summary":"List clients","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `clients:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt","name","-name","status","-status"],"default":"-createdAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: name, sector.","schema":{"type":"string"}},{"name":"filter[status]","in":"query","description":"Exact match on `status`.","schema":{"type":"string"}},{"name":"filter[sector]","in":"query","description":"Exact match on `sector`.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Clients"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createClients","tags":["Clients"],"summary":"Create a client","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientsCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Clients"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getClients","tags":["Clients"],"summary":"Retrieve a client","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `clients:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Clients"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateClients","tags":["Clients"],"summary":"Update a client","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `clients:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientsUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Clients"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteClients","tags":["Clients"],"summary":"Delete a client","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `clients:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/actions":{"get":{"operationId":"listClientsActions","tags":["Clients"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `clients:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/add-portal-highlight":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsAddPortalHighlight","tags":["Clients"],"summary":"Pin a quick access","description":"Pins a highlighted link (\"Quick access\") to the home page of this client's portal.\n\nDoes what the dashboard's `addPortalHighlightAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":80},"url":{"type":"string","maxLength":500,"format":"uri"}},"required":["label","url"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/remove-portal-highlight":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsRemovePortalHighlight","tags":["Clients"],"summary":"Remove a quick access","description":"Removes the pinned link pointing at this URL from the client's portal home. If several point there under different names, pass `label` to say which.\n\nDoes what the dashboard's `deletePortalHighlightAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","maxLength":500,"format":"uri"},"label":{"type":"string","minLength":1,"maxLength":80}},"required":["url"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/set-portal-permission":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsSetPortalPermission","tags":["Clients"],"summary":"Set a portal permission","description":"Grants or removes a portal permission for one of the client's members, identified by e-mail. If the state you ask for matches their role's preset, the exception is lifted and the member inherits from the role again.\n\nDoes what the dashboard's `setMemberPortalPermissionAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","maxLength":200,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"permissionKey":{"type":"string","enum":["billing.read","docs.read","forfaits.read","reports.read","decks.read","tickets.create","chat.write"]},"allowed":{"type":"boolean"}},"required":["email","permissionKey","allowed"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/submit-onboarding":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsSubmitOnboarding","tags":["Clients"],"summary":"Submit onboarding for review","description":"Submits the onboarding this client filled in for the agency to review. Refused while a required step is still outstanding, so it never stands in for the client's own work. Pass `projectId` when several onboardings are open.\n\nDoes what the dashboard's `submitOnboardingAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"projectId":{"type":"string","minLength":1}}}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/validate-onboarding":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsValidateOnboarding","tags":["Clients"],"summary":"Approve the onboarding","description":"Approves the onboarding this client submitted and opens their portal. Pass `projectId` when several onboardings are open.\n\nDoes what the dashboard's `validateOnboardingAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"projectId":{"type":"string","minLength":1}}}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/request-onboarding-changes":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsRequestOnboardingChanges","tags":["Clients"],"summary":"Request onboarding changes","description":"Sends the submitted onboarding back to the client with a note explaining what needs adjusting. Pass `projectId` when several onboardings are open.\n\nDoes what the dashboard's `requestOnboardingChangesAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"projectId":{"type":"string","minLength":1},"note":{"type":"string","minLength":1,"maxLength":2000}},"required":["note"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/cancel-onboarding":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsCancelOnboarding","tags":["Clients"],"summary":"Cancel the onboarding","description":"Cancels this client's onboarding, unlocking their portal without approving it. Pass `projectId` when several onboardings are open.\n\nDoes what the dashboard's `cancelOnboardingAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"projectId":{"type":"string","minLength":1},"note":{"type":"string","maxLength":2000}}}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/link-drive-folder":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsLinkDriveFolder","tags":["Clients"],"summary":"Link a Google Drive folder","description":"Links a Google Drive folder to the client, by URL or folder id, after checking it exists through the Drive API. Replaces any previously linked folder, and stays hidden from the portal by default.\n\nDoes what the dashboard's `linkDriveFolderAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"folder":{"type":"string","minLength":1,"maxLength":2000},"clientVisible":{"type":"boolean"}},"required":["folder"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/set-drive-visibility":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsSetDriveVisibility","tags":["Clients"],"summary":"Set Drive folder visibility","description":"Shows (`clientVisible: true`) or hides (`false`) the linked Drive folder in the client's portal.\n\nDoes what the dashboard's `toggleDriveVisibilityAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"clientVisible":{"type":"boolean"}},"required":["clientVisible"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/unlink-drive-folder":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsUnlinkDriveFolder","tags":["Clients"],"summary":"Unlink the Drive folder","description":"Removes the link between the client and their Google Drive folder. The folder itself is untouched.\n\nDoes what the dashboard's `unlinkDriveFolderAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/start-crawl":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsStartCrawl","tags":["Clients"],"summary":"Start a crawl","description":"Starts crawling this client's website (the sitemap tool). Requires a plan with SEO (Pro and above, trials included); capped at 2,000 pages per crawl, counted against the monthly allowance. The job is queued and runs in the background.\n\nDoes what the dashboard's `startCrawlAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","minLength":1,"maxLength":2000}},"required":["url"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/cancel-crawl":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsCancelCrawl","tags":["Clients"],"summary":"Cancel the running crawl","description":"Stops the running or queued crawl for this client. Pages already explored are kept.\n\nDoes what the dashboard's `cancelCrawlAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/set-crawl-schedule":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsSetCrawlSchedule","tags":["Clients"],"summary":"Schedule the monthly re-crawl","description":"Turns the automatic monthly re-crawl of this client's site on (`monthly`) or off (`off`).\n\nDoes what the dashboard's `setCrawlScheduleAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"schedule":{"type":"string","enum":["off","monthly"]}},"required":["schedule"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/add-note":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsAddNote","tags":["Clients"],"summary":"Add an internal note","description":"Writes an internal note on this client's record, optionally attached to one of their deals. Never visible to the client.\n\nDoes what the dashboard's `addAccountNoteAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":4000},"dealId":{"type":"string","minLength":1}},"required":["body"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/start-offboarding":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsStartOffboarding","tags":["Clients"],"summary":"Start offboarding","description":"Opens an offboarding for this client and creates the default end-of-contract checklist.\n\nDoes what the dashboard's `startOffboardingAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/toggle-offboarding-step":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsToggleOffboardingStep","tags":["Clients"],"summary":"Tick or untick an offboarding step","description":"Marks a step of the offboarding checklist as done (`done: true`) or not, addressed by its zero-based position.\n\nDoes what the dashboard's `toggleOffboardingStepAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"position":{"type":"integer","minimum":0,"maximum":9007199254740991},"done":{"type":"boolean"}},"required":["position","done"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/cancel-offboarding":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsCancelOffboarding","tags":["Clients"],"summary":"Cancel the offboarding","description":"Cancels this client's offboarding. The checklist is abandoned.\n\nDoes what the dashboard's `cancelOffboardingAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/complete-offboarding":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsCompleteOffboarding","tags":["Clients"],"summary":"Complete the offboarding","description":"Completes this client's offboarding: archives the account and sends the farewell e-mail, carrying the agency's review links, to their portal users.\n\nDoes what the dashboard's `completeOffboardingAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/request-nps":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsRequestNps","tags":["Clients"],"summary":"Request an NPS rating","description":"Invites this client's portal users to leave an NPS rating, by in-app notification and e-mail according to their preferences.\n\nDoes what the dashboard's `requestNpsAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/withdraw-nps":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsWithdrawNps","tags":["Clients"],"summary":"Withdraw the NPS request","description":"Takes the review card off this client's portal home again. A rating already given stays.\n\nDoes what the dashboard's `withdrawNpsAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/propose-suggestion":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsProposeSuggestion","tags":["Clients"],"summary":"Propose a suggestion","description":"Proposes an improvement on this client's portal — title, pitch, effort, benefit, optionally a linked project — and notifies their users. The client accepts or declines from their portal.\n\nDoes what the dashboard's `createSuggestionAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":2,"maxLength":160},"description":{"type":"string","maxLength":2000},"effort":{"type":"string","maxLength":80},"benefit":{"type":"string","maxLength":300},"projectId":{"type":"string","minLength":1}},"required":["title"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/sync-connectors":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsSyncConnectors","tags":["Clients"],"summary":"Sync the connectors","description":"Immediately re-runs the capture for every active connection of this client. The response lists which connectors were captured and which failed — each connection fails on its own.\n\nDoes what the dashboard's `refreshAccountConnectionsAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/actions/import-csv":{"post":{"operationId":"runClientsImportCsv","tags":["Clients"],"summary":"Import a CSV","description":"Imports clients or contacts from CSV text (headers on the first line) with a column-to-field mapping. Invalid rows are skipped and itemised in the response (`imported` / `skipped` / `errors`). For contacts, the `account` column must match the exact name of an existing client.\n\nDoes what the dashboard's `importCsvAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","enum":["clients","contacts"]},"csv":{"type":"string","minLength":1,"maxLength":2000000},"mapping":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}}},"required":["type","csv","mapping"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/link-object":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsLinkObject","tags":["Clients"],"summary":"Link to an object","description":"Creates a relation between this record and a target object (`targetType` plus the target's public `targetId`) in the relation graph. Linking the same pair twice does nothing.\n\nDoes what the dashboard's `linkObjectAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"targetType":{"type":"string","enum":["account","contact","project","ticket","deal","user","proposal"]},"targetId":{"type":"string","minLength":1,"maxLength":60}},"required":["targetType","targetId"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/unlink-object":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsUnlinkObject","tags":["Clients"],"summary":"Unlink an object","description":"Removes the relation between this record and the target object in the relation graph. Unlinking a pair that was never linked does nothing.\n\nDoes what the dashboard's `unlinkObjectAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"targetType":{"type":"string","enum":["account","contact","project","ticket","deal","user","proposal"]},"targetId":{"type":"string","minLength":1,"maxLength":60}},"required":["targetType","targetId"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/set-manager":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsSetManager","tags":["Clients"],"summary":"Assign the account manager","description":"Assigns this client to the agency member who looks after it, named by its id from `/v1/members`. `null` clears the assignment.\n\nDoes what the dashboard's `setAccountManagerAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"managerId":{"anyOf":[{"type":"string","minLength":1,"maxLength":60},{"type":"null"}]}},"required":["managerId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/set-team":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsSetTeam","tags":["Clients"],"summary":"Assign the team","description":"Assigns this client to the team that carries it, named by its id from `/v1/teams`. `null` clears the assignment.\n\nDoes what the dashboard's `setAccountTeamAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"teamId":{"anyOf":[{"type":"string","minLength":1,"maxLength":60},{"type":"null"}]}},"required":["teamId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}/actions/set-logo":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runClientsSetLogo","tags":["Clients"],"summary":"Set the logo","description":"Stores the client's logo as a data URI (PNG, JPEG or WebP, already resized). `null` removes the logo.\n\nDoes what the dashboard's `setAccountLogoAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"logo":{"anyOf":[{"type":"string","maxLength":96000,"pattern":"^data:image\\/(png|jpeg|webp);base64,[A-Za-z0-9+/=]+$"},{"type":"null"}]}},"required":["logo"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/actions/set-overview-layout":{"post":{"operationId":"runClientsSetOverviewLayout","tags":["Clients"],"summary":"Configure the client overview panel","description":"Sets, for the whole agency, which rows appear in the overview panel of a client record and in what order. Each entry is a built-in key (`sector`, `status`, `website`, `siren`, `since`, `hours`, `openTickets`, `activeProjects`, `openDeals`, `contacts`, `lastActivity`) or `field:<key>` for a client custom field. Unknown rows are ignored; an empty list restores the default.\n\nDoes what the dashboard's `saveClientOverviewAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `clients:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rows":{"maxItems":40,"type":"array","items":{"type":"string","minLength":1,"maxLength":80}}},"required":["rows"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/contacts":{"get":{"operationId":"listContacts","tags":["Contacts"],"summary":"List contacts","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `contacts:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt","name","-name"],"default":"-createdAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: name, email.","schema":{"type":"string"}},{"name":"filter[isDecisionMaker]","in":"query","description":"Exact match on `isDecisionMaker`.","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Contacts"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createContacts","tags":["Contacts"],"summary":"Create a contact","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `contacts:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactsCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Contacts"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/contacts/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getContacts","tags":["Contacts"],"summary":"Retrieve a contact","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `contacts:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Contacts"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateContacts","tags":["Contacts"],"summary":"Update a contact","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `contacts:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactsUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Contacts"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteContacts","tags":["Contacts"],"summary":"Delete a contact","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `contacts:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/contacts/actions":{"get":{"operationId":"listContactsActions","tags":["Contacts"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `contacts:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/contacts/{id}/actions/link-object":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runContactsLinkObject","tags":["Contacts"],"summary":"Link to an object","description":"Creates a relation between this record and a target object (`targetType` plus the target's public `targetId`) in the relation graph. Linking the same pair twice does nothing.\n\nDoes what the dashboard's `linkObjectAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `contacts:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"targetType":{"type":"string","enum":["account","contact","project","ticket","deal","user","proposal"]},"targetId":{"type":"string","minLength":1,"maxLength":60}},"required":["targetType","targetId"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/contacts/{id}/actions/unlink-object":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runContactsUnlinkObject","tags":["Contacts"],"summary":"Unlink an object","description":"Removes the relation between this record and the target object in the relation graph. Unlinking a pair that was never linked does nothing.\n\nDoes what the dashboard's `unlinkObjectAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `contacts:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"targetType":{"type":"string","enum":["account","contact","project","ticket","deal","user","proposal"]},"targetId":{"type":"string","minLength":1,"maxLength":60}},"required":["targetType","targetId"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/contacts/{id}/actions/link-account":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runContactsLinkAccount","tags":["Contacts"],"summary":"Attach to an organisation","description":"Links this person to the given client, or updates the job title and the e-mail address they use at that organisation. The first link becomes their primary organisation.\n\nDoes what the dashboard's `linkContactAccountAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `contacts:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"clientId":{"type":"string","minLength":1,"maxLength":60},"title":{"type":"string","maxLength":80},"email":{"anyOf":[{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},{"type":"string","const":""}]}},"required":["clientId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/contacts/{id}/actions/unlink-account":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runContactsUnlinkAccount","tags":["Contacts"],"summary":"Detach from an organisation","description":"Removes the link between this person and the given client. If it was their primary organisation, another link takes over.\n\nDoes what the dashboard's `unlinkContactAccountAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `contacts:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"clientId":{"type":"string","minLength":1,"maxLength":60}},"required":["clientId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/contacts/{id}/actions/set-primary-account":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runContactsSetPrimaryAccount","tags":["Contacts"],"summary":"Set the primary organisation","description":"Makes the given client this person's primary organisation — the one single-company views show. The other links are kept.\n\nDoes what the dashboard's `setPrimaryAccountAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `contacts:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"clientId":{"type":"string","minLength":1,"maxLength":60}},"required":["clientId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/contacts/{id}/actions/merge":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runContactsMerge","tags":["Contacts"],"summary":"Merge people into this one","description":"Folds the given contacts into this one: its empty fields are filled from theirs, everything that named them (deals, activities, calls, organisations) now names this contact, and they are deleted. Irreversible.\n\nDoes what the dashboard's `mergeContactsAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `contacts:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contactIds":{"minItems":1,"maxItems":100,"type":"array","items":{"type":"string","minLength":1,"maxLength":60}}},"required":["contactIds"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/contacts/{id}/actions/set-avatar":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runContactsSetAvatar","tags":["Contacts"],"summary":"Set the picture","description":"Stores the person's picture as a data URI (PNG, JPEG or WebP, already resized). `null` removes it.\n\nDoes what the dashboard's `setContactAvatarAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `contacts:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"avatar":{"anyOf":[{"type":"string","maxLength":96000,"pattern":"^data:image\\/(png|jpeg|webp);base64,[A-Za-z0-9+/=]+$"},{"type":"null"}]}},"required":["avatar"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deals":{"get":{"operationId":"listDeals","tags":["Deals"],"summary":"List deals","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `deals:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt","updatedAt","-updatedAt","valueCents","-valueCents","name","-name"],"default":"-updatedAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: name.","schema":{"type":"string"}},{"name":"filter[status]","in":"query","description":"Exact match on `status`.","schema":{"type":"string","enum":["open","won","lost"]}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Deals"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createDeals","tags":["Deals"],"summary":"Create a deal","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `deals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DealsCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Deals"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deals/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getDeals","tags":["Deals"],"summary":"Retrieve a deal","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `deals:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Deals"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateDeals","tags":["Deals"],"summary":"Update a deal","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `deals:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DealsUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Deals"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteDeals","tags":["Deals"],"summary":"Delete a deal","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `deals:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deals/actions":{"get":{"operationId":"listDealsActions","tags":["Deals"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `deals:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deals/{id}/actions/close":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDealsClose","tags":["Deals"],"summary":"Close or reopen the deal","description":"Wins, loses or reopens the deal without moving it between stages. Winning signs the organisation and opens the delivery project (or attaches one of the client's existing projects via `attachProject`), and may open that project to the deal's delivery partners via `sharePartners`; losing requires a reason from the catalogue, given by its label.\n\nDoes what the dashboard's `closeDealAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `deals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"outcome":{"type":"string","enum":["won","lost","reopen"]},"reason":{"type":"string","maxLength":120},"note":{"type":"string","maxLength":1000},"attachProject":{"type":"string","maxLength":40},"sharePartners":{"maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":60}}},"required":["outcome"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deals/{id}/actions/convert-to-lead":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDealsConvertToLead","tags":["Deals"],"summary":"Convert back to a lead","description":"Recreates a qualified lead from the deal — organisation, contact, notes — then archives the deal, so the pipeline keeps the history of what was attempted.\n\nDoes what the dashboard's `convertDealToLeadAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `deals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deals/{id}/actions/duplicate":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDealsDuplicate","tags":["Deals"],"summary":"Duplicate the deal","description":"Copies the deal into a new opportunity on the same organisation, carrying value, contact, buying committee and product lines. The copy starts again at the pipeline's first stage.\n\nDoes what the dashboard's `duplicateDealAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `deals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deals/{id}/actions/merge":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDealsMerge","tags":["Deals"],"summary":"Merge into another deal","description":"Merges this deal into the target deal: activities, notes, product lines and buying committee move across, then this deal is deleted.\n\nDoes what the dashboard's `mergeDealsAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `deals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"targetDealId":{"type":"string","minLength":1,"maxLength":60}},"required":["targetDealId"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deals/{id}/actions/set-archived":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDealsSetArchived","tags":["Deals"],"summary":"Archive or restore","description":"Archives the deal — it leaves the board without losing its history — or restores it when `archived` is false.\n\nDoes what the dashboard's `setDealArchivedAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `deals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"archived":{"type":"boolean"}},"required":["archived"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deals/{id}/actions/set-owner":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDealsSetOwner","tags":["Deals"],"summary":"Change the owner","description":"Reassigns sales ownership of the deal to an agency member (see `/v1/members`), or clears it with `ownerId: null`.\n\nDoes what the dashboard's `setDealOwnerAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `deals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ownerId":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}]}}}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deals/{id}/actions/upsert-contact":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDealsUpsertContact","tags":["Deals"],"summary":"Add or re-grade a contact","description":"Attaches an existing contact to the deal's buying committee with their weight (decision-maker, influencer, participant), or updates that weight if they are already on it.\n\nDoes what the dashboard's `upsertDealContactAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `deals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contactId":{"type":"string","minLength":1,"maxLength":60},"role":{"type":"string","enum":["decision_maker","influencer","participant"]}},"required":["contactId","role"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deals/{id}/actions/remove-contact":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDealsRemoveContact","tags":["Deals"],"summary":"Remove a contact","description":"Removes a contact from the deal's buying committee. The contact record itself is kept.\n\nDoes what the dashboard's `removeDealContactAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `deals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contactId":{"type":"string","minLength":1,"maxLength":60}},"required":["contactId"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deals/{id}/actions/add-product":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDealsAddProduct","tags":["Deals"],"summary":"Add a product line","description":"Appends a line to what the deal sells: name, quantity and unit price in cents.\n\nDoes what the dashboard's `addDealProductAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `deals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"quantity":{"default":1,"type":"number","exclusiveMinimum":0,"maximum":1000000},"unitAmountCents":{"default":0,"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["name"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deals/{id}/actions/remove-product":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDealsRemoveProduct","tags":["Deals"],"summary":"Remove a product line","description":"Removes a line from what the deal sells, addressed by its public id. List the lines with `/v1/deal-products?filter[dealId]=…`.\n\nDoes what the dashboard's `removeDealProductAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `deals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"lineId":{"type":"string","minLength":1,"maxLength":60}},"required":["lineId"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deals/{id}/actions/link-object":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDealsLinkObject","tags":["Deals"],"summary":"Link to an object","description":"Creates a relation between this record and a target object (`targetType` plus the target's public `targetId`) in the relation graph. Linking the same pair twice does nothing.\n\nDoes what the dashboard's `linkObjectAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `deals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"targetType":{"type":"string","enum":["account","contact","project","ticket","deal","user","proposal"]},"targetId":{"type":"string","minLength":1,"maxLength":60}},"required":["targetType","targetId"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deals/{id}/actions/unlink-object":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDealsUnlinkObject","tags":["Deals"],"summary":"Unlink an object","description":"Removes the relation between this record and the target object in the relation graph. Unlinking a pair that was never linked does nothing.\n\nDoes what the dashboard's `unlinkObjectAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `deals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"targetType":{"type":"string","enum":["account","contact","project","ticket","deal","user","proposal"]},"targetId":{"type":"string","minLength":1,"maxLength":60}},"required":["targetType","targetId"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deals/{id}/actions/move-to-pipeline":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDealsMoveToPipeline","tags":["Deals"],"summary":"Move the deal to another pipeline","description":"Moves the deal to another sales pipeline. The destination stage is required and must belong to the target pipeline — stages do not map from one pipeline to another.\n\nDoes what the dashboard's `moveDealToPipelineAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `deals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"pipelineId":{"type":"string","minLength":1,"maxLength":60},"stageId":{"type":"string","minLength":1,"maxLength":60}},"required":["pipelineId","stageId"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deals/{id}/actions/set-primary-contact":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDealsSetPrimaryContact","tags":["Deals"],"summary":"Set the primary contact","description":"Makes this contact the deal's primary contact, adding them to the buying committee if they were not on it. Their weight on the committee is left alone.\n\nDoes what the dashboard's `setDealPrimaryContactAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `deals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contactId":{"type":"string","minLength":1,"maxLength":60}},"required":["contactId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/leads":{"get":{"operationId":"listLeads","tags":["Leads"],"summary":"List leads","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `leads:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt","lastContactedAt","-lastContactedAt","companyName","-companyName"],"default":"-createdAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: companyName, contactName, email.","schema":{"type":"string"}},{"name":"filter[status]","in":"query","description":"Exact match on `status`.","schema":{"type":"string","enum":["to_contact","contacted","following_up","qualified","converted","disqualified"]}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Leads"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createLeads","tags":["Leads"],"summary":"Create a lead","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `leads:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadsCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Leads"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/leads/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getLeads","tags":["Leads"],"summary":"Retrieve a lead","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `leads:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Leads"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateLeads","tags":["Leads"],"summary":"Update a lead","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `leads:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadsUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Leads"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteLeads","tags":["Leads"],"summary":"Delete a lead","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `leads:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/leads/actions":{"get":{"operationId":"listLeadsActions","tags":["Leads"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `leads:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/leads/{id}/actions/convert":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runLeadsConvert","tags":["Leads"],"summary":"Convert to a deal","description":"Turns the lead into a deal: the organisation and the contact are linked or created, the deal lands on the stage you choose (or the first one), and the lead is marked converted with a pointer to the deal.\n\nDoes what the dashboard's `convertLeadAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `leads:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"dealName":{"type":"string","maxLength":200},"stageId":{"type":"string","maxLength":60}}}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/projects":{"get":{"operationId":"listProjects","tags":["Projects"],"summary":"List projects","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `projects:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt","name","-name","status","-status"],"default":"-createdAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: name.","schema":{"type":"string"}},{"name":"filter[status]","in":"query","description":"Exact match on `status`.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Projects"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createProjects","tags":["Projects"],"summary":"Create a project","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `projects:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectsCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Projects"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/projects/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getProjects","tags":["Projects"],"summary":"Retrieve a project","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `projects:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Projects"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateProjects","tags":["Projects"],"summary":"Update a project","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `projects:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectsUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Projects"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteProjects","tags":["Projects"],"summary":"Delete a project","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `projects:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/projects/actions":{"get":{"operationId":"listProjectsActions","tags":["Projects"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `projects:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/projects/{id}/actions/share-with-partner":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runProjectsShareWithPartner","tags":["Projects"],"summary":"Share with a partner","description":"Shares this project with an already-linked partner agency. Idempotent: re-sharing reactivates a revoked share.\n\nDoes what the dashboard's `shareProjectAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `projects:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"partnerOrgId":{"type":"string","minLength":1}},"required":["partnerOrgId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/projects/{id}/actions/revoke-share":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runProjectsRevokeShare","tags":["Projects"],"summary":"Revoke a share","description":"Removes a partner agency's access to this shared project.\n\nDoes what the dashboard's `revokeProjectShareAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `projects:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"partnerOrgId":{"type":"string","minLength":1}},"required":["partnerOrgId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/projects/{id}/actions/invite-person":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runProjectsInvitePerson","tags":["Projects"],"summary":"Invite a person by email","description":"Invites an outside person onto this project by email — creating the CRM person, the partner and the seat when needed — and shares the project with them. Idempotent on the address: re-running refreshes the invitation link. `allowTime` is only honoured on a new share.\n\nDoes what the dashboard's `inviteOnProjectAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `projects:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"name":{"type":"string","maxLength":120},"allowTime":{"type":"boolean"}},"required":["email"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/projects/{id}/actions/add-member":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runProjectsAddMember","tags":["Projects"],"summary":"Add a member to the project","description":"Adds an agency member to this project. `memberId` is the member's user id, the one the `members` resource returns. Already assigned does nothing.\n\nDoes what the dashboard's `addProjectMemberAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `projects:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"memberId":{"type":"string","minLength":1}},"required":["memberId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/projects/{id}/actions/remove-member":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runProjectsRemoveMember","tags":["Projects"],"summary":"Remove a member from the project","description":"Removes an agency member from this project. `memberId` is the member's user id. Not assigned does nothing.\n\nDoes what the dashboard's `removeProjectMemberAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `projects:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"memberId":{"type":"string","minLength":1}},"required":["memberId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/projects/{id}/actions/link-object":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runProjectsLinkObject","tags":["Projects"],"summary":"Link to an object","description":"Creates a relation between this record and a target object (`targetType` plus the target's public `targetId`) in the relation graph. Linking the same pair twice does nothing.\n\nDoes what the dashboard's `linkObjectAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `projects:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"targetType":{"type":"string","enum":["account","contact","project","ticket","deal","user","proposal"]},"targetId":{"type":"string","minLength":1,"maxLength":60}},"required":["targetType","targetId"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/projects/{id}/actions/unlink-object":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runProjectsUnlinkObject","tags":["Projects"],"summary":"Unlink an object","description":"Removes the relation between this record and the target object in the relation graph. Unlinking a pair that was never linked does nothing.\n\nDoes what the dashboard's `unlinkObjectAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `projects:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"targetType":{"type":"string","enum":["account","contact","project","ticket","deal","user","proposal"]},"targetId":{"type":"string","minLength":1,"maxLength":60}},"required":["targetType","targetId"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/tickets":{"get":{"operationId":"listTickets","tags":["Tickets"],"summary":"List tickets","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `tickets:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt","dueDate","-dueDate","priority","-priority","status","-status","resolvedAt","-resolvedAt"],"default":"-createdAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: title, description.","schema":{"type":"string"}},{"name":"filter[status]","in":"query","description":"Exact match on `status`.","schema":{"type":"string"}},{"name":"filter[priority]","in":"query","description":"Exact match on `priority`.","schema":{"type":"string","enum":["low","medium","high","urgent"]}},{"name":"filter[scope]","in":"query","description":"Exact match on `scope`.","schema":{"type":"string","enum":["client","agency","internal"]}},{"name":"filter[clientVisible]","in":"query","description":"Exact match on `clientVisible`.","schema":{"type":"string","enum":["true","false"]}},{"name":"filter[clientId]","in":"query","description":"Exact match on `clientId`.","schema":{"type":"string"}},{"name":"filter[projectId]","in":"query","description":"Exact match on `projectId`.","schema":{"type":"string"}},{"name":"filter[parentId]","in":"query","description":"Exact match on `parentId`.","schema":{"type":"string"}},{"name":"filter[assigneeId]","in":"query","description":"Exact match on `assigneeId`.","schema":{"type":"string"}},{"name":"filter[categoryId]","in":"query","description":"Exact match on `categoryId`.","schema":{"type":"string"}},{"name":"filter[teamId]","in":"query","description":"Exact match on `teamId`.","schema":{"type":"string"}},{"name":"filter[open]","in":"query","description":"`true` for tickets not yet in a terminal column of the agency's workflow, `false` for the finished ones. Reads the agency's own columns, never the literal `done`.","schema":{"type":"string","enum":["true","false"]}},{"name":"filter[archived]","in":"query","description":"`false` (the default) leaves archived tickets out; `true` lists only them. Put away with `bulk-update { archived: true }`.","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Tickets"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createTickets","tags":["Tickets"],"summary":"Create a ticket","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `tickets:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketsCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Tickets"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/tickets/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getTickets","tags":["Tickets"],"summary":"Retrieve a ticket","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `tickets:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Tickets"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateTickets","tags":["Tickets"],"summary":"Update a ticket","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `tickets:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketsUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Tickets"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteTickets","tags":["Tickets"],"summary":"Delete a ticket","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `tickets:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/tickets/actions":{"get":{"operationId":"listTicketsActions","tags":["Tickets"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `tickets:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/tickets/{id}/actions/add-dependency":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runTicketsAddDependency","tags":["Tickets"],"summary":"Add a dependency","description":"Declares that this ticket is blocked by another one (`dependsOnId`). Refuses self-blocking and an immediate reverse dependency.\n\nDoes what the dashboard's `addTicketDependencyAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `tickets:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"dependsOnId":{"type":"string","minLength":1}},"required":["dependsOnId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/tickets/{id}/actions/remove-dependency":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runTicketsRemoveDependency","tags":["Tickets"],"summary":"Remove a dependency","description":"Removes the \"blocked by\" link between this ticket and the ticket named by `dependsOnId`.\n\nDoes what the dashboard's `removeTicketDependencyAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `tickets:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"dependsOnId":{"type":"string","minLength":1}},"required":["dependsOnId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/tickets/{id}/actions/upload-attachment":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runTicketsUploadAttachment","tags":["Tickets"],"summary":"Attach a file","description":"Adds an attachment to this ticket: base64 content, 5 MB maximum once decoded, stored in the private bucket and visible in the dashboard straight away.\n\nDoes what the dashboard's `uploadAttachmentAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `tickets:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fileName":{"type":"string","minLength":1,"maxLength":200},"contentType":{"type":"string","maxLength":120},"data":{"type":"string","maxLength":6990508,"format":"base64","contentEncoding":"base64","pattern":"^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$"}},"required":["fileName","data"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/tickets/{id}/actions/delete-attachment":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runTicketsDeleteAttachment","tags":["Tickets"],"summary":"Delete an attachment","description":"Deletes this ticket's attachment with the given filename, row and stored file alike. Refused when two of the ticket's attachments share that name.\n\nDoes what the dashboard's `deleteAttachmentAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `tickets:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fileName":{"type":"string","minLength":1,"maxLength":200}},"required":["fileName"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/tickets/{id}/actions/link-object":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runTicketsLinkObject","tags":["Tickets"],"summary":"Link to an object","description":"Creates a relation between this record and a target object (`targetType` plus the target's public `targetId`) in the relation graph. Linking the same pair twice does nothing.\n\nDoes what the dashboard's `linkObjectAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `tickets:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"targetType":{"type":"string","enum":["account","contact","project","ticket","deal","user","proposal"]},"targetId":{"type":"string","minLength":1,"maxLength":60}},"required":["targetType","targetId"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/tickets/{id}/actions/unlink-object":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runTicketsUnlinkObject","tags":["Tickets"],"summary":"Unlink an object","description":"Removes the relation between this record and the target object in the relation graph. Unlinking a pair that was never linked does nothing.\n\nDoes what the dashboard's `unlinkObjectAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `tickets:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"targetType":{"type":"string","enum":["account","contact","project","ticket","deal","user","proposal"]},"targetId":{"type":"string","minLength":1,"maxLength":60}},"required":["targetType","targetId"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/tickets/actions/bulk-update":{"post":{"operationId":"runTicketsBulkUpdate","tags":["Tickets"],"summary":"Update several tickets","description":"Applies the same change — status, priority, category, assignee, archived — to at most 200 tickets in a single write. The status is checked against the agency's workflow columns.\n\nDoes what the dashboard's `bulkUpdateWorkItemsAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `tickets:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"itemIds":{"minItems":1,"maxItems":200,"type":"array","items":{"type":"string","minLength":1,"maxLength":60}},"status":{"type":"string","minLength":1,"maxLength":40},"priority":{"type":"string","enum":["low","medium","high","urgent"]},"archived":{"type":"boolean"},"categoryId":{"anyOf":[{"type":"string","minLength":1,"maxLength":60},{"type":"null"}]},"assigneeId":{"anyOf":[{"type":"string","minLength":1,"maxLength":64},{"type":"null"}]}},"required":["itemIds"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/tickets/{id}/actions/set-content":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runTicketsSetContent","tags":["Tickets"],"summary":"Save a ticket's rich content","description":"Replaces the ticket's body (a BlockNote document) and rewrites its plain-text description at the same time — the one the portal, the e-mails and search read.\n\nDoes what the dashboard's `setTicketContentAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `tickets:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content":{"maxItems":2000,"type":"array","items":{}}},"required":["content"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/tickets/actions/save-workflow":{"post":{"operationId":"runTicketsSaveWorkflow","tags":["Tickets"],"summary":"Save the workflow columns","description":"Replaces the agency's workflow columns wholesale — between 2 and 12, at least one terminal and one non-terminal. Tickets left in a deleted column move to the first non-terminal column, and the response says how many.\n\nDoes what the dashboard's `saveWorkflowAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `tickets:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"columns":{"minItems":2,"maxItems":12,"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":40},"label":{"type":"string","minLength":1,"maxLength":40},"color":{"type":"string","enum":["slate","blue","amber","emerald","violet","rose"]},"isDone":{"type":"boolean"}},"required":["label","color","isDone"],"additionalProperties":false}}},"required":["columns"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/tickets/actions/reset-workflow":{"post":{"operationId":"runTicketsResetWorkflow","tags":["Tickets"],"summary":"Reset the workflow","description":"Restores the five columns the product ships with, moving tickets left in a deleted column to the first non-terminal one.\n\nDoes what the dashboard's `resetWorkflowAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `tickets:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/time-logs":{"get":{"operationId":"listTimeLogs","tags":["Time logs"],"summary":"List time logs","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `time-logs:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["startedAt","-startedAt","createdAt","-createdAt","durationMinutes","-durationMinutes"],"default":"-startedAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: note.","schema":{"type":"string"}},{"name":"filter[billable]","in":"query","description":"Exact match on `billable`.","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TimeLogs"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createTimeLogs","tags":["Time logs"],"summary":"Create a time log","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `time-logs:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeLogsCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TimeLogs"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/time-logs/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getTimeLogs","tags":["Time logs"],"summary":"Retrieve a time log","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `time-logs:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TimeLogs"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateTimeLogs","tags":["Time logs"],"summary":"Update a time log","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `time-logs:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeLogsUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TimeLogs"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteTimeLogs","tags":["Time logs"],"summary":"Delete a time log","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `time-logs:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/time-logs/actions":{"get":{"operationId":"listTimeLogsActions","tags":["Time logs"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `time-logs:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/time-logs/actions/running-timer":{"post":{"operationId":"runTimeLogsRunningTimer","tags":["Time logs"],"summary":"Running timer","description":"Returns the running timer of the user the key belongs to — ticket, client, note, minutes elapsed — or `running: false` when none is going.\n\nDoes what the dashboard's `getMyTimerAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `time-logs:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/time-logs/actions/start-timer":{"post":{"operationId":"runTimeLogsStartTimer","tags":["Time logs"],"summary":"Start the timer","description":"Starts a timer for the user the key belongs to, optionally on a ticket. Any timer already running is stopped and logged, and the response says how many minutes that recorded.\n\nDoes what the dashboard's `startTimerAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `time-logs:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ticketId":{"anyOf":[{"type":"string","minLength":1,"maxLength":60},{"type":"null"}]},"note":{"type":"string","maxLength":500}},"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/time-logs/actions/stop-timer":{"post":{"operationId":"runTimeLogsStopTimer","tags":["Time logs"],"summary":"Stop the timer","description":"Stops the running timer and records it as time spent. Under a minute records nothing. Fails when no timer is running.\n\nDoes what the dashboard's `stopTimerAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `time-logs:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/time-logs/actions/discard-timer":{"post":{"operationId":"runTimeLogsDiscardTimer","tags":["Time logs"],"summary":"Discard the timer","description":"Drops the running timer without recording any time. Does nothing when none is running.\n\nDoes what the dashboard's `discardTimerAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `time-logs:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/workflow-statuses":{"get":{"operationId":"listWorkflowStatuses","tags":["Workflow columns"],"summary":"List workflow columns","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `workflow-statuses:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["position","-position","label","-label"],"default":"position"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: label.","schema":{"type":"string"}},{"name":"filter[isDone]","in":"query","description":"Exact match on `isDone`.","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WorkflowStatuses"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/workflow-statuses/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getWorkflowStatuses","tags":["Workflow columns"],"summary":"Retrieve a workflow column","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `workflow-statuses:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/WorkflowStatuses"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/workflow-statuses/actions":{"get":{"operationId":"listWorkflowStatusesActions","tags":["Workflow columns"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `workflow-statuses:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/forfaits":{"get":{"operationId":"listForfaits","tags":["Retainers"],"summary":"List retainers","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `forfaits:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt","periodStart","-periodStart"],"default":"-createdAt"}},{"name":"filter[type]","in":"query","description":"Exact match on `type`.","schema":{"type":"string","enum":["monthly","project","quarterly","semiannual","annual"]}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Forfaits"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createForfaits","tags":["Retainers"],"summary":"Create a retainer","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `forfaits:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForfaitsCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Forfaits"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/forfaits/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getForfaits","tags":["Retainers"],"summary":"Retrieve a retainer","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `forfaits:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Forfaits"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateForfaits","tags":["Retainers"],"summary":"Update a retainer","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `forfaits:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForfaitsUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Forfaits"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteForfaits","tags":["Retainers"],"summary":"Delete a retainer","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `forfaits:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/forfaits/actions":{"get":{"operationId":"listForfaitsActions","tags":["Retainers"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `forfaits:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/docs":{"get":{"operationId":"listDocs","tags":["Docs"],"summary":"List docs","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `docs:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["updatedAt","-updatedAt","createdAt","-createdAt","title","-title"],"default":"-updatedAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: title, body.","schema":{"type":"string"}},{"name":"filter[clientVisible]","in":"query","description":"Exact match on `clientVisible`.","schema":{"type":"string","enum":["true","false"]}},{"name":"filter[portalScope]","in":"query","description":"Exact match on `portalScope`.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Docs"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createDocs","tags":["Docs"],"summary":"Create a doc","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `docs:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocsCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Docs"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/docs/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getDocs","tags":["Docs"],"summary":"Retrieve a doc","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `docs:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Docs"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateDocs","tags":["Docs"],"summary":"Update a doc","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `docs:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocsUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Docs"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteDocs","tags":["Docs"],"summary":"Delete a doc","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `docs:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/docs/actions":{"get":{"operationId":"listDocsActions","tags":["Docs"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `docs:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/docs/{id}/actions/move":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDocsMove","tags":["Docs"],"summary":"Move to a folder","description":"Files the doc in the given folder (a public id from `/v1/doc-folders`), or at the root when `folderId` is null or absent.\n\nDoes what the dashboard's `moveDocAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `docs:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"folderId":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}]}}}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/docs/{id}/actions/relocate":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDocsRelocate","tags":["Docs"],"summary":"Move within the tree","description":"Places the doc under another doc — it becomes a sub-page and follows that doc's folder — into a folder when only `folderId` is given, or at the root when both are null. A move into its own descendants is refused, and portal visibility is never widened.\n\nDoes what the dashboard's `moveDocToAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `docs:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"parentId":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}]},"folderId":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}]}},"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/docs/{id}/actions/pin":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDocsPin","tags":["Docs"],"summary":"Put forward on the docs page","description":"Puts the doc on the front row of the agency's docs page (`pinned: true`, newest pin first) or takes it back (`false`). Agency-side only: the portal never reads it.\n\nDoes what the dashboard's `toggleDocPinAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `docs:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"pinned":{"type":"boolean"}},"required":["pinned"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/categories":{"get":{"operationId":"listCategories","tags":["Categories"],"summary":"List categories","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `categories:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt","name","-name"],"default":"name"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: name.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Categories"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/categories/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getCategories","tags":["Categories"],"summary":"Retrieve a category","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `categories:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Categories"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/categories/actions":{"get":{"operationId":"listCategoriesActions","tags":["Categories"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `categories:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/teams":{"get":{"operationId":"listTeams","tags":["Teams"],"summary":"List teams","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `teams:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["position","-position","name","-name","createdAt","-createdAt"],"default":"position"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: name.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Teams"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/teams/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getTeams","tags":["Teams"],"summary":"Retrieve a team","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `teams:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Teams"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/teams/actions":{"get":{"operationId":"listTeamsActions","tags":["Teams"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `teams:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/teams/{id}/actions/rename":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runTeamsRename","tags":["Teams"],"summary":"Rename the team","description":"Renames the team. 60 characters maximum.\n\nDoes what the dashboard's `renameTeamAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `teams:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":60}},"required":["name"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/teams/{id}/actions/set-membership":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runTeamsSetMembership","tags":["Teams"],"summary":"Add or remove a member","description":"Adds (`member: true`) or removes (`member: false`) a member from the team, by their id from `/v1/members`.\n\nDoes what the dashboard's `setTeamMembershipAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `teams:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","minLength":1},"member":{"type":"boolean"}},"required":["userId","member"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/pipelines":{"get":{"operationId":"listPipelines","tags":["Pipelines"],"summary":"List pipelines","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `pipelines:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["position","-position","name","-name","createdAt","-createdAt"],"default":"position"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: name.","schema":{"type":"string"}},{"name":"filter[isDefault]","in":"query","description":"Exact match on `isDefault`.","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Pipelines"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createPipelines","tags":["Pipelines"],"summary":"Create a pipeline","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `pipelines:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelinesCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Pipelines"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/pipelines/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getPipelines","tags":["Pipelines"],"summary":"Retrieve a pipeline","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `pipelines:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Pipelines"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updatePipelines","tags":["Pipelines"],"summary":"Update a pipeline","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `pipelines:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelinesUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Pipelines"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deletePipelines","tags":["Pipelines"],"summary":"Delete a pipeline","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `pipelines:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/pipelines/actions":{"get":{"operationId":"listPipelinesActions","tags":["Pipelines"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `pipelines:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/pipelines/actions/set-default":{"post":{"operationId":"runPipelinesSetDefault","tags":["Pipelines"],"summary":"Set the default pipeline","description":"Names the pipeline a deal lands in when none is chosen explicitly — import, API, lead conversion. Whichever pipeline held the title loses it in the same transaction.\n\nDoes what the dashboard's `setDefaultPipelineAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `pipelines:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"pipelineId":{"type":"string","minLength":1,"maxLength":60}},"required":["pipelineId"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/pipelines/actions/move":{"post":{"operationId":"runPipelinesMove","tags":["Pipelines"],"summary":"Reorder a pipeline","description":"Swaps the pipeline with its neighbour above or below. With no neighbour that way, the order is left as it is.\n\nDoes what the dashboard's `movePipelineAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `pipelines:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"pipelineId":{"type":"string","minLength":1,"maxLength":60},"direction":{"type":"string","enum":["up","down"]}},"required":["pipelineId","direction"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/pipeline-stages":{"get":{"operationId":"listPipelineStages","tags":["Pipeline stages"],"summary":"List pipeline stages","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `pipeline-stages:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["position","-position","name","-name","createdAt","-createdAt"],"default":"position"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: name.","schema":{"type":"string"}},{"name":"filter[kind]","in":"query","description":"Exact match on `kind`.","schema":{"type":"string","enum":["open","won","lost"]}},{"name":"filter[pipelineId]","in":"query","description":"Exact match on `pipelineId`.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PipelineStages"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/pipeline-stages/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getPipelineStages","tags":["Pipeline stages"],"summary":"Retrieve a pipeline stage","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `pipeline-stages:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PipelineStages"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/pipeline-stages/actions":{"get":{"operationId":"listPipelineStagesActions","tags":["Pipeline stages"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `pipeline-stages:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/pipeline-stages/actions/move":{"post":{"operationId":"runPipelineStagesMove","tags":["Pipeline stages"],"summary":"Reorder a stage","description":"Swaps the stage with its neighbour above or below in the pipeline's order. With no neighbour that way, the order is left as it is.\n\nDoes what the dashboard's `moveStageAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `pipeline-stages:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"stageId":{"type":"string","minLength":1,"maxLength":60},"direction":{"type":"string","enum":["up","down"]}},"required":["stageId","direction"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/members":{"get":{"operationId":"listMembers","tags":["Members"],"summary":"List members","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `members:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt","name","-name","role","-role"],"default":"createdAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: name, email.","schema":{"type":"string"}},{"name":"filter[role]","in":"query","description":"Exact match on `role`.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Members"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/members/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getMembers","tags":["Members"],"summary":"Retrieve a member","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `members:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Members"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/members/actions":{"get":{"operationId":"listMembersActions","tags":["Members"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `members:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/members/actions/invite":{"post":{"operationId":"runMembersInvite","tags":["Members"],"summary":"Invite a member","description":"Invites an e-mail address to join the agency, as `member` or `owner`. Refused once the plan's seats are used up — active members and pending invitations both count. The invitee gets the same e-mail as from the dashboard, and the invitation expires after 48 hours.\n\nDoes what the dashboard's `inviteMemberAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `members:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","maxLength":200,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"role":{"default":"member","type":"string","enum":["member","owner"]}},"required":["email"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/members/{id}/actions/remove":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runMembersRemove","tags":["Members"],"summary":"Remove the member","description":"Removes this member from the agency. Their user account is kept.\n\nDoes what the dashboard's `removeMemberAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `members:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/members/actions/cancel-invitation":{"post":{"operationId":"runMembersCancelInvitation","tags":["Members"],"summary":"Cancel an invitation","description":"Cancels the pending invitations sent to this e-mail address to join the agency.\n\nDoes what the dashboard's `cancelInvitationAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `members:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","maxLength":200,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"}},"required":["email"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/members/{id}/actions/set-cost-rate":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runMembersSetCostRate","tags":["Members"],"summary":"Set the internal hourly cost","description":"Sets this member's internal hourly cost in euros, used by project profitability. `null` clears it.\n\nDoes what the dashboard's `setMemberRateAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `members:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"costRateEuros":{"anyOf":[{"type":"number","minimum":0,"maximum":100000},{"type":"null"}]}},"required":["costRateEuros"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/members/{id}/actions/link-object":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runMembersLinkObject","tags":["Members"],"summary":"Link to an object","description":"Creates a relation between this record and a target object (`targetType` plus the target's public `targetId`) in the relation graph. Linking the same pair twice does nothing.\n\nDoes what the dashboard's `linkObjectAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `members:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"targetType":{"type":"string","enum":["account","contact","project","ticket","deal","user","proposal"]},"targetId":{"type":"string","minLength":1,"maxLength":60}},"required":["targetType","targetId"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/members/{id}/actions/unlink-object":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runMembersUnlinkObject","tags":["Members"],"summary":"Unlink an object","description":"Removes the relation between this record and the target object in the relation graph. Unlinking a pair that was never linked does nothing.\n\nDoes what the dashboard's `unlinkObjectAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `members:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"targetType":{"type":"string","enum":["account","contact","project","ticket","deal","user","proposal"]},"targetId":{"type":"string","minLength":1,"maxLength":60}},"required":["targetType","targetId"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/field-definitions":{"get":{"operationId":"listFieldDefinitions","tags":["Custom fields"],"summary":"List custom fields","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `field-definitions:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["position","-position","createdAt","-createdAt","label","-label"],"default":"position"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: label, key.","schema":{"type":"string"}},{"name":"filter[entity]","in":"query","description":"Exact match on `entity`.","schema":{"type":"string","enum":["ticket","deal","account","lead","contact"]}},{"name":"filter[type]","in":"query","description":"Exact match on `type`.","schema":{"type":"string","enum":["text","long_text","number","date","select","multi_select","checkbox","url","user","email"]}},{"name":"filter[archived]","in":"query","description":"Exact match on `archived`.","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/FieldDefinitions"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createFieldDefinitions","tags":["Custom fields"],"summary":"Create a custom field","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `field-definitions:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FieldDefinitionsCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/FieldDefinitions"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/field-definitions/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getFieldDefinitions","tags":["Custom fields"],"summary":"Retrieve a custom field","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `field-definitions:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/FieldDefinitions"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateFieldDefinitions","tags":["Custom fields"],"summary":"Update a custom field","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `field-definitions:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FieldDefinitionsUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/FieldDefinitions"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteFieldDefinitions","tags":["Custom fields"],"summary":"Delete a custom field","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `field-definitions:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/field-definitions/actions":{"get":{"operationId":"listFieldDefinitionsActions","tags":["Custom fields"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `field-definitions:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/field-definitions/actions/reorder":{"post":{"operationId":"runFieldDefinitionsReorder","tags":["Custom fields"],"summary":"Reorder the fields","description":"Reorders the field definitions: each field's position becomes its index in the list of ids you send.\n\nDoes what the dashboard's `reorderFieldDefinitionsAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `field-definitions:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ids":{"minItems":1,"maxItems":500,"type":"array","items":{"type":"string","minLength":1}}},"required":["ids"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/comments":{"get":{"operationId":"listComments","tags":["Comments"],"summary":"List comments","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `comments:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt"],"default":"-createdAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: body.","schema":{"type":"string"}},{"name":"filter[clientVisible]","in":"query","description":"Exact match on `clientVisible`.","schema":{"type":"string","enum":["true","false"]}},{"name":"filter[ticketId]","in":"query","description":"Exact match on `ticketId`.","schema":{"type":"string"}},{"name":"filter[parentId]","in":"query","description":"Exact match on `parentId`.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Comments"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createComments","tags":["Comments"],"summary":"Create a comment","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `comments:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentsCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Comments"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/comments/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getComments","tags":["Comments"],"summary":"Retrieve a comment","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `comments:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Comments"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateComments","tags":["Comments"],"summary":"Update a comment","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `comments:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentsUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Comments"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteComments","tags":["Comments"],"summary":"Delete a comment","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `comments:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/comments/actions":{"get":{"operationId":"listCommentsActions","tags":["Comments"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `comments:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/activities":{"get":{"operationId":"listActivities","tags":["Activities"],"summary":"List activities","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `activities:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["startAt","-startAt","createdAt","-createdAt","title","-title"],"default":"-startAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: title, note.","schema":{"type":"string"}},{"name":"filter[type]","in":"query","description":"Exact match on `type`.","schema":{"type":"string"}},{"name":"filter[done]","in":"query","description":"Exact match on `done`.","schema":{"type":"string","enum":["true","false"]}},{"name":"filter[priority]","in":"query","description":"Exact match on `priority`.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Activities"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createActivities","tags":["Activities"],"summary":"Create a activity","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `activities:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivitiesCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Activities"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/activities/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getActivities","tags":["Activities"],"summary":"Retrieve a activity","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `activities:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Activities"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateActivities","tags":["Activities"],"summary":"Update a activity","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `activities:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivitiesUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Activities"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteActivities","tags":["Activities"],"summary":"Delete a activity","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `activities:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/activities/actions":{"get":{"operationId":"listActivitiesActions","tags":["Activities"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `activities:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/proposals":{"get":{"operationId":"listProposals","tags":["Proposals"],"summary":"List proposals","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `proposals:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["updatedAt","-updatedAt","createdAt","-createdAt","title","-title","status","-status"],"default":"-updatedAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: title, clientName.","schema":{"type":"string"}},{"name":"filter[status]","in":"query","description":"Exact match on `status`.","schema":{"type":"string","enum":["draft","sent","viewed","accepted","declined","paid"]}},{"name":"filter[locale]","in":"query","description":"Exact match on `locale`.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Proposals"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createProposals","tags":["Proposals"],"summary":"Create a proposal","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `proposals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProposalsCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Proposals"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/proposals/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getProposals","tags":["Proposals"],"summary":"Retrieve a proposal","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `proposals:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Proposals"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateProposals","tags":["Proposals"],"summary":"Update a proposal","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `proposals:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProposalsUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Proposals"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteProposals","tags":["Proposals"],"summary":"Delete a proposal","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `proposals:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/proposals/actions":{"get":{"operationId":"listProposalsActions","tags":["Proposals"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `proposals:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/proposals/{id}/actions/new-version":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runProposalsNewVersion","tags":["Proposals"],"summary":"Create the next version","description":"Duplicates the current proposal as version N+1 — document, theme, terms — and leaves the old public link redirecting to it. The new version starts as a draft.\n\nDoes what the dashboard's `createProposalVersionAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `proposals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/proposals/{id}/actions/update-settings":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runProposalsUpdateSettings","tags":["Proposals"],"summary":"Update the settings","description":"Saves the proposal's settings: the client name shown, the language of the public page, the currency and the public slug.\n\nDoes what the dashboard's `saveProposalSettingsAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `proposals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"clientName":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"locale":{"type":"string","minLength":2,"maxLength":12},"currency":{"type":"string","minLength":3,"maxLength":3},"publicSlug":{"anyOf":[{"type":"string","maxLength":80,"pattern":"^[a-z0-9-]+$"},{"type":"null"}]}},"required":["locale","currency"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/proposals/{id}/actions/set-theme":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runProposalsSetTheme","tags":["Proposals"],"summary":"Set the theme","description":"Applies a visual theme to the proposal's public page — colours, block styling — or `null` to inherit the agency's branding.\n\nDoes what the dashboard's `saveProposalThemeAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `proposals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"theme":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]}},"required":["theme"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/proposals/{id}/actions/set-password":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runProposalsSetPassword","tags":["Proposals"],"summary":"Set the password","description":"Protects the proposal's public page with a password, stored hashed. An empty password removes the protection.\n\nDoes what the dashboard's `setProposalPasswordAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `proposals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"password":{"type":"string","maxLength":200}},"required":["password"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/proposals/{id}/actions/set-sharing":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runProposalsSetSharing","tags":["Proposals"],"summary":"Turn sharing on or off","description":"Turns the proposal's public link on — minting a share token and returning the URL — or off, revoking the token.\n\nDoes what the dashboard's `toggleSharingAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `proposals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"}},"required":["enabled"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/proposals/actions/upload-image":{"post":{"operationId":"runProposalsUploadImage","tags":["Proposals"],"summary":"Upload an image","description":"Uploads an image for the content blocks (base64, 5 MB maximum) and returns the public delivery URL to reference from an image block.\n\nDoes what the dashboard's `uploadProposalImageAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `proposals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fileName":{"type":"string","minLength":1,"maxLength":200},"contentType":{"type":"string","maxLength":120,"pattern":"^image\\/"},"data":{"type":"string","maxLength":6990508,"format":"base64","contentEncoding":"base64","pattern":"^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$"}},"required":["fileName","contentType","data"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/proposals/{id}/actions/set-payment-settings":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runProposalsSetPaymentSettings","tags":["Proposals"],"summary":"Set the payment options","description":"Saves the proposal's payment options: the Stripe payment button on the public page, the button pinned at the bottom, and bank transfer details (`null` to remove them).\n\nDoes what the dashboard's `saveProposalPaymentSettingsAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `proposals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enableStripe":{"type":"boolean"},"stickyPay":{"type":"boolean"},"bankTransfer":{"anyOf":[{"type":"object","properties":{"label":{"type":"string","maxLength":200},"iban":{"type":"string","maxLength":60},"bic":{"type":"string","maxLength":20},"reference":{"type":"string","maxLength":200},"terms":{"type":"string","maxLength":2000}}},{"type":"null"}]}}}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/proposals/actions/publish-template":{"post":{"operationId":"runProposalsPublishTemplate","tags":["Proposals"],"summary":"Publish a template to the marketplace","description":"Publishes one of the agency's templates — theme or document, named by its exact name — to the cross-agency marketplace. The agency's name is shown as the author.\n\nDoes what the dashboard's `publishTemplateAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `proposals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"scope":{"type":"string","enum":["theme","document"]}},"required":["name"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/proposals/actions/install-marketplace-template":{"post":{"operationId":"runProposalsInstallMarketplaceTemplate","tags":["Proposals"],"summary":"Install a template from the marketplace","description":"Copies a template published on the marketplace into the agency's template library, and bumps its install count. Name it by its exact name, plus `authorName` when several share it.\n\nDoes what the dashboard's `installMarketplaceAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `proposals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"authorName":{"type":"string","maxLength":200}},"required":["name"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/proposals/{id}/actions/link-object":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runProposalsLinkObject","tags":["Proposals"],"summary":"Link to an object","description":"Creates a relation between this record and a target object (`targetType` plus the target's public `targetId`) in the relation graph. Linking the same pair twice does nothing.\n\nDoes what the dashboard's `linkObjectAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `proposals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"targetType":{"type":"string","enum":["account","contact","project","ticket","deal","user","proposal"]},"targetId":{"type":"string","minLength":1,"maxLength":60}},"required":["targetType","targetId"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/proposals/{id}/actions/unlink-object":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runProposalsUnlinkObject","tags":["Proposals"],"summary":"Unlink an object","description":"Removes the relation between this record and the target object in the relation graph. Unlinking a pair that was never linked does nothing.\n\nDoes what the dashboard's `unlinkObjectAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `proposals:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"targetType":{"type":"string","enum":["account","contact","project","ticket","deal","user","proposal"]},"targetId":{"type":"string","minLength":1,"maxLength":60}},"required":["targetType","targetId"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/reports":{"get":{"operationId":"listReports","tags":["Reports"],"summary":"List reports","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `reports:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["updatedAt","-updatedAt","createdAt","-createdAt","name","-name"],"default":"-updatedAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: name.","schema":{"type":"string"}},{"name":"filter[portalVisible]","in":"query","description":"Exact match on `portalVisible`.","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Reports"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createReports","tags":["Reports"],"summary":"Create a report","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `reports:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportsCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Reports"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/reports/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getReports","tags":["Reports"],"summary":"Retrieve a report","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `reports:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Reports"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateReports","tags":["Reports"],"summary":"Update a report","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `reports:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportsUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Reports"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteReports","tags":["Reports"],"summary":"Delete a report","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `reports:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/reports/actions":{"get":{"operationId":"listReportsActions","tags":["Reports"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `reports:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/reports/{id}/actions/duplicate":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runReportsDuplicate","tags":["Reports"],"summary":"Duplicate the report","description":"Copies the report, carrying its layout and period, with \"(copie)\" appended to the name. The public share link is never copied.\n\nDoes what the dashboard's `duplicateReportAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `reports:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/reports/{id}/actions/set-sharing":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runReportsSetSharing","tags":["Reports"],"summary":"Turn the public link on or off","description":"Turns the report's public share link on, returning the token — re-enabling an already-active link rotates it — or off, revoking the token.\n\nDoes what the dashboard's `setReportSharingAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `reports:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"}},"required":["enabled"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/reports/{id}/actions/save-as-template":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runReportsSaveAsTemplate","tags":["Reports"],"summary":"Save the report as a template","description":"Copies the report's layout and period into a reusable agency template under the name you give, and returns the template's public id — which is what `save-schedule` then takes.\n\nDoes what the dashboard's `saveReportAsTemplateAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `reports:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120}},"required":["name"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/reports/actions/save-schedule":{"post":{"operationId":"runReportsSaveSchedule","tags":["Reports"],"summary":"Schedule a monthly report","description":"Turns on automatic generation of a report for this client from the given template, on the 1st of each month. Calling it again with the same client and template updates the schedule rather than creating a second one. `portalVisible` defaults to true.\n\nDoes what the dashboard's `saveReportScheduleAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `reports:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"clientId":{"type":"string","minLength":1,"maxLength":60},"templateId":{"type":"string","minLength":1,"maxLength":60},"portalVisible":{"default":true,"type":"boolean"}},"required":["clientId","templateId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/report-templates":{"get":{"operationId":"listReportTemplates","tags":["Report templates"],"summary":"List report templates","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `report-templates:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["name","-name","createdAt","-createdAt","updatedAt","-updatedAt"],"default":"name"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: name.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ReportTemplates"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/report-templates/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getReportTemplates","tags":["Report templates"],"summary":"Retrieve a report template","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `report-templates:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ReportTemplates"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteReportTemplates","tags":["Report templates"],"summary":"Delete a report template","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `report-templates:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/report-templates/actions":{"get":{"operationId":"listReportTemplatesActions","tags":["Report templates"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `report-templates:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/report-schedules":{"get":{"operationId":"listReportSchedules","tags":["Report schedules"],"summary":"List report schedules","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `report-schedules:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt","updatedAt","-updatedAt","lastRunAt","-lastRunAt"],"default":"-createdAt"}},{"name":"filter[active]","in":"query","description":"Exact match on `active`.","schema":{"type":"string","enum":["true","false"]}},{"name":"filter[portalVisible]","in":"query","description":"Exact match on `portalVisible`.","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ReportSchedules"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/report-schedules/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getReportSchedules","tags":["Report schedules"],"summary":"Retrieve a report schedule","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `report-schedules:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ReportSchedules"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteReportSchedules","tags":["Report schedules"],"summary":"Delete a report schedule","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `report-schedules:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/report-schedules/actions":{"get":{"operationId":"listReportSchedulesActions","tags":["Report schedules"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `report-schedules:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/chat-channels":{"get":{"operationId":"listChatChannels","tags":["Chat channels"],"summary":"List chat channels","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `chat-channels:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["position","-position","createdAt","-createdAt","name","-name"],"default":"position"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: name.","schema":{"type":"string"}},{"name":"filter[audience]","in":"query","description":"Exact match on `audience`.","schema":{"type":"string","enum":["all","internal","partners"]}},{"name":"filter[projectId]","in":"query","description":"Exact match on `projectId`.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ChatChannels"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createChatChannels","tags":["Chat channels"],"summary":"Create a chat channel","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `chat-channels:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatChannelsCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ChatChannels"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/chat-channels/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getChatChannels","tags":["Chat channels"],"summary":"Retrieve a chat channel","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `chat-channels:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ChatChannels"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateChatChannels","tags":["Chat channels"],"summary":"Update a chat channel","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `chat-channels:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatChannelsUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ChatChannels"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteChatChannels","tags":["Chat channels"],"summary":"Delete a chat channel","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `chat-channels:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/chat-channels/actions":{"get":{"operationId":"listChatChannelsActions","tags":["Chat channels"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `chat-channels:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/chat-channels/{id}/actions/send-message":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runChatChannelsSendMessage","tags":["Chat channels"],"summary":"Send a message","description":"Posts a message in this channel as the user who issued the key, and broadcasts it live to the participants. `parentId` — the public id of a message in the channel — makes it a thread reply, anchored to the thread's root.\n\nDoes what the dashboard's `sendChatMessageAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `chat-channels:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":4000},"parentId":{"type":"string","minLength":1,"maxLength":40}},"required":["body"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/chat-messages":{"get":{"operationId":"listChatMessages","tags":["Chat messages"],"summary":"List chat messages","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `chat-messages:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt"],"default":"-createdAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: body.","schema":{"type":"string"}},{"name":"filter[channelId]","in":"query","description":"Exact match on `channelId`.","schema":{"type":"string"}},{"name":"filter[projectId]","in":"query","description":"Exact match on `projectId`.","schema":{"type":"string"}},{"name":"filter[parentId]","in":"query","description":"Exact match on `parentId`.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ChatMessages"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createChatMessages","tags":["Chat messages"],"summary":"Create a chat message","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `chat-messages:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatMessagesCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ChatMessages"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/chat-messages/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getChatMessages","tags":["Chat messages"],"summary":"Retrieve a chat message","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `chat-messages:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ChatMessages"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateChatMessages","tags":["Chat messages"],"summary":"Update a chat message","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `chat-messages:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatMessagesUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ChatMessages"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteChatMessages","tags":["Chat messages"],"summary":"Delete a chat message","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `chat-messages:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/chat-messages/actions":{"get":{"operationId":"listChatMessagesActions","tags":["Chat messages"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `chat-messages:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/decks":{"get":{"operationId":"listDecks","tags":["Decks"],"summary":"List decks","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `decks:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["updatedAt","-updatedAt","createdAt","-createdAt","name","-name"],"default":"-updatedAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: name.","schema":{"type":"string"}},{"name":"filter[portalVisible]","in":"query","description":"Exact match on `portalVisible`.","schema":{"type":"string","enum":["true","false"]}},{"name":"filter[dataMode]","in":"query","description":"Exact match on `dataMode`.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Decks"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createDecks","tags":["Decks"],"summary":"Create a deck","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `decks:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DecksCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Decks"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/decks/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getDecks","tags":["Decks"],"summary":"Retrieve a deck","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `decks:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Decks"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateDecks","tags":["Decks"],"summary":"Update a deck","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `decks:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DecksUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Decks"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteDecks","tags":["Decks"],"summary":"Delete a deck","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `decks:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/decks/actions":{"get":{"operationId":"listDecksActions","tags":["Decks"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `decks:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/decks/{id}/actions/duplicate":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDecksDuplicate","tags":["Decks"],"summary":"Duplicate","description":"Copies the deck (\"… (copie)\") onto the same client and project. The copy starts in live mode, with no public link and no portal publication.\n\nDoes what the dashboard's `duplicateDeckAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `decks:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/decks/{id}/actions/unfreeze":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDecksUnfreeze","tags":["Decks"],"summary":"Switch back to live","description":"Puts a frozen deck back into live mode: the frozen data is cleared and every view recomputes the figures from the latest captures.\n\nDoes what the dashboard's `unfreezeDeckAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `decks:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/decks/{id}/actions/save-guides":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDecksSaveGuides","tags":["Decks"],"summary":"Save the guides","description":"Replaces the editor's ruler guides — pixel positions on the 1280×720 canvas, as `v` and `h` lists. A placement aid only; it changes nothing in the output.\n\nDoes what the dashboard's `saveDeckGuidesAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `decks:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"guides":{"type":"object","properties":{"v":{"default":[],"maxItems":50,"type":"array","items":{"type":"number","minimum":0,"maximum":1280}},"h":{"default":[],"maxItems":50,"type":"array","items":{"type":"number","minimum":0,"maximum":720}}}}},"required":["guides"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/decks/{id}/actions/freeze":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDecksFreeze","tags":["Decks"],"summary":"Freeze","description":"Resolves the live widgets one last time, from the connectors' latest captures, and freezes the result: the deck stops following the data and shows that point in time.\n\nDoes what the dashboard's `freezeDeckAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `decks:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/decks/{id}/actions/set-sharing":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDecksSetSharing","tags":["Decks"],"summary":"Public link","description":"Turns the deck's public link on, rotates it, or turns it off. `enabled: true` on a deck with no link activates it — freezing a still-live deck, as the dashboard does; on an already-shared deck it rotates the token. `enabled: false` cuts the link. Responds with the `token`, or null.\n\nDoes what the dashboard's `setDeckSharingAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `decks:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"}},"required":["enabled"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/decks/actions/save-theme":{"post":{"operationId":"runDecksSaveTheme","tags":["Decks"],"summary":"Save a theme","description":"Creates the theme with this name, or replaces its tokens if it already exists. An agency's first theme becomes its default. The name identifies the theme, so two themes sharing one make the call fail.\n\nDoes what the dashboard's `saveDeckThemeAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `decks:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80},"tokens":{"type":"object","properties":{"palette":{"type":"object","properties":{"bg":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"surface":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"text":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"muted":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"accent":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"onAccent":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"chart":{"minItems":3,"maxItems":6,"type":"array","items":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}}},"required":["bg","surface","text","muted","accent","onAccent","chart"]},"fonts":{"type":"object","properties":{"heading":{"type":"string","enum":["sans","serif","mono","rounded","condensed","display","grotesk"]},"body":{"type":"string","enum":["sans","serif","mono","rounded","condensed","display","grotesk"]}},"required":["heading","body"]},"text":{"type":"object","properties":{"title":{"type":"object","properties":{"px":{"type":"integer","minimum":8,"maximum":200},"weight":{"type":"integer","minimum":100,"maximum":900},"color":{"type":"string","enum":["bg","surface","text","muted","accent","onAccent"]},"font":{"type":"string","enum":["heading","body"]},"tracking":{"default":0,"type":"number","minimum":-0.1,"maximum":0.4},"uppercase":{"default":false,"type":"boolean"}},"required":["px","weight","color","font"]},"heading":{"type":"object","properties":{"px":{"type":"integer","minimum":8,"maximum":200},"weight":{"type":"integer","minimum":100,"maximum":900},"color":{"type":"string","enum":["bg","surface","text","muted","accent","onAccent"]},"font":{"type":"string","enum":["heading","body"]},"tracking":{"default":0,"type":"number","minimum":-0.1,"maximum":0.4},"uppercase":{"default":false,"type":"boolean"}},"required":["px","weight","color","font"]},"subheading":{"type":"object","properties":{"px":{"type":"integer","minimum":8,"maximum":200},"weight":{"type":"integer","minimum":100,"maximum":900},"color":{"type":"string","enum":["bg","surface","text","muted","accent","onAccent"]},"font":{"type":"string","enum":["heading","body"]},"tracking":{"default":0,"type":"number","minimum":-0.1,"maximum":0.4},"uppercase":{"default":false,"type":"boolean"}},"required":["px","weight","color","font"]},"body":{"type":"object","properties":{"px":{"type":"integer","minimum":8,"maximum":200},"weight":{"type":"integer","minimum":100,"maximum":900},"color":{"type":"string","enum":["bg","surface","text","muted","accent","onAccent"]},"font":{"type":"string","enum":["heading","body"]},"tracking":{"default":0,"type":"number","minimum":-0.1,"maximum":0.4},"uppercase":{"default":false,"type":"boolean"}},"required":["px","weight","color","font"]},"caption":{"type":"object","properties":{"px":{"type":"integer","minimum":8,"maximum":200},"weight":{"type":"integer","minimum":100,"maximum":900},"color":{"type":"string","enum":["bg","surface","text","muted","accent","onAccent"]},"font":{"type":"string","enum":["heading","body"]},"tracking":{"default":0,"type":"number","minimum":-0.1,"maximum":0.4},"uppercase":{"default":false,"type":"boolean"}},"required":["px","weight","color","font"]}},"required":["title","heading","subheading","body","caption"]}},"required":["palette","fonts","text"]},"isDefault":{"default":false,"type":"boolean"}},"required":["name","tokens"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/decks/actions/add-theme-preset":{"post":{"operationId":"runDecksAddThemePreset","tags":["Decks"],"summary":"Adopt a preset theme","description":"Copies one of the shipped themes into the agency's catalogue, where it becomes editable (ardoise, encre, papier, foret, nuit). The call fails when a theme already carries that name, so an edited palette is never overwritten.\n\nDoes what the dashboard's `addDeckThemePresetAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `decks:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"preset":{"type":"string"}},"required":["preset"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/decks/actions/delete-theme":{"post":{"operationId":"runDecksDeleteTheme","tags":["Decks"],"summary":"Delete a theme","description":"Removes the theme from the agency's catalogue. Decks that followed it fall back to the default theme, their slides unchanged.\n\nDoes what the dashboard's `deleteDeckThemeAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `decks:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"theme":{"type":"string","minLength":1,"maxLength":80}},"required":["theme"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/decks/{id}/actions/set-theme":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDecksSetTheme","tags":["Decks"],"summary":"Apply a theme","description":"Points the deck at the named theme, or at the agency's default when `theme` is null. Only the link is written: an element set to a token repaints, an element set to a raw value keeps it.\n\nDoes what the dashboard's `setDeckThemeAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `decks:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"theme":{"anyOf":[{"type":"string","minLength":1,"maxLength":80},{"type":"null"}]}},"required":["theme"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/decks/{id}/actions/save-as-template":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDecksSaveAsTemplate","tags":["Decks"],"summary":"Save as a template","description":"Copies the deck's layout and period into a reusable agency template under the name you give. The template then seeds a new deck or a monthly generation; it is not readable through the API.\n\nDoes what the dashboard's `saveDeckAsTemplateAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `decks:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120}},"required":["name"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/decks/actions/save-schedule":{"post":{"operationId":"runDecksSaveSchedule","tags":["Decks"],"summary":"Schedule a monthly deck","description":"Turns on automatic generation of a deck for this client from the named template, on the 1st of each month. Calling it again with the same client and template updates the schedule rather than creating a second one.\n\nDoes what the dashboard's `saveDeckScheduleAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `decks:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"clientId":{"type":"string","minLength":1,"maxLength":60},"template":{"type":"string","minLength":1,"maxLength":120},"portalVisible":{"default":true,"type":"boolean"}},"required":["clientId","template"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deck-comments":{"get":{"operationId":"listDeckComments","tags":["Deck comments"],"summary":"List deck comments","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `deck-comments:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt","slideIndex","-slideIndex"],"default":"-createdAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: body, authorName.","schema":{"type":"string"}},{"name":"filter[slideIndex]","in":"query","description":"Exact match on `slideIndex`.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DeckComments"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deck-comments/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getDeckComments","tags":["Deck comments"],"summary":"Retrieve a deck comment","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `deck-comments:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/DeckComments"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deck-comments/actions":{"get":{"operationId":"listDeckCommentsActions","tags":["Deck comments"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `deck-comments:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deck-comments/{id}/actions/resolve":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDeckCommentsResolve","tags":["Deck comments"],"summary":"Resolve a comment","description":"Marks a client's slide comment as dealt with, or reopens it with {resolved: false}. The comment itself is kept either way — only the open counter changes.\n\nDoes what the dashboard's `resolveDeckCommentAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `deck-comments:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"resolved":{"default":true,"type":"boolean"}},"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/portal-invitations":{"get":{"operationId":"listPortalInvitations","tags":["Portal invitations"],"summary":"List portal invitations","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `portal-invitations:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt","expiresAt","-expiresAt","email","-email"],"default":"-createdAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: email.","schema":{"type":"string"}},{"name":"filter[status]","in":"query","description":"Exact match on `status`.","schema":{"type":"string"}},{"name":"filter[roleKey]","in":"query","description":"Exact match on `roleKey`.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PortalInvitations"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createPortalInvitations","tags":["Portal invitations"],"summary":"Create a portal invitation","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `portal-invitations:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortalInvitationsCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PortalInvitations"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/portal-invitations/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getPortalInvitations","tags":["Portal invitations"],"summary":"Retrieve a portal invitation","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `portal-invitations:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PortalInvitations"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updatePortalInvitations","tags":["Portal invitations"],"summary":"Update a portal invitation","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `portal-invitations:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortalInvitationsUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PortalInvitations"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deletePortalInvitations","tags":["Portal invitations"],"summary":"Delete a portal invitation","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `portal-invitations:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/portal-invitations/actions":{"get":{"operationId":"listPortalInvitationsActions","tags":["Portal invitations"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `portal-invitations:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/connector-connections":{"get":{"operationId":"listConnectorConnections","tags":["Connectors"],"summary":"List connectors","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `connector-connections:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt","updatedAt","-updatedAt","connectorId","-connectorId"],"default":"-createdAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: connectorId.","schema":{"type":"string"}},{"name":"filter[connectorId]","in":"query","description":"Exact match on `connectorId`.","schema":{"type":"string"}},{"name":"filter[enabled]","in":"query","description":"Exact match on `enabled`.","schema":{"type":"string","enum":["true","false"]}},{"name":"filter[portalVisible]","in":"query","description":"Exact match on `portalVisible`.","schema":{"type":"string","enum":["true","false"]}},{"name":"filter[status]","in":"query","description":"Exact match on `status`.","schema":{"type":"string"}},{"name":"filter[frequency]","in":"query","description":"Exact match on `frequency`.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ConnectorConnections"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createConnectorConnections","tags":["Connectors"],"summary":"Create a connector","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `connector-connections:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorConnectionsCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ConnectorConnections"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/connector-connections/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getConnectorConnections","tags":["Connectors"],"summary":"Retrieve a connector","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `connector-connections:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ConnectorConnections"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateConnectorConnections","tags":["Connectors"],"summary":"Update a connector","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `connector-connections:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorConnectionsUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ConnectorConnections"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteConnectorConnections","tags":["Connectors"],"summary":"Delete a connector","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `connector-connections:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/connector-connections/actions":{"get":{"operationId":"listConnectorConnectionsActions","tags":["Connectors"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `connector-connections:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/connector-connections/{id}/actions/sync":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runConnectorConnectionsSync","tags":["Connectors"],"summary":"Sync now","description":"Re-runs this connection's capture immediately — snapshot plus metric series — without waiting for its frequency window. The outcome, status and last error, is recorded on the connection.\n\nDoes what the dashboard's `refreshConnectionAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `connector-connections:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings":{"get":{"operationId":"listAgencySettings","tags":["Agency settings"],"summary":"List agency settings","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `agency-settings:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["updatedAt","-updatedAt"],"default":"-updatedAt"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AgencySettings"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getAgencySettings","tags":["Agency settings"],"summary":"Retrieve a agency setting","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `agency-settings:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AgencySettings"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions":{"get":{"operationId":"listAgencySettingsActions","tags":["Agency settings"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `agency-settings:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/save-settings":{"post":{"operationId":"runAgencySettingsSaveSettings","tags":["Agency settings"],"summary":"Save the preferences","description":"Writes the agency's operational preferences — IANA time zone, whether retainer hours show on the portal, review links — replacing the whole map.\n\nDoes what the dashboard's `saveAgencySettingsAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"timezone":{"type":"string"},"portalShowForfaitHours":{"type":"boolean"},"reviewLinks":{"maxItems":10,"type":"array","items":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":60},"url":{"type":"string","maxLength":500,"format":"uri"},"rating":{"type":"number","minimum":0,"maximum":5},"count":{"type":"integer","minimum":0,"maximum":1000000}},"required":["label","url"]}}},"required":["currency","timezone","portalShowForfaitHours","reviewLinks"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/save-client-create-fields":{"post":{"operationId":"runAgencySettingsSaveClientCreateFields","tags":["Agency settings"],"summary":"Client form fields","description":"Chooses which built-in columns (`sector`, `website`, `siren`) the add-client form asks for. An empty list is valid; the name is always asked for.\n\nDoes what the dashboard's `saveClientCreateFieldsAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fields":{"type":"array","items":{"type":"string","enum":["sector","website","siren"]}}},"required":["fields"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/save-nps-template":{"post":{"operationId":"runAgencySettingsSaveNpsTemplate","tags":["Agency settings"],"summary":"NPS request e-mail","description":"Writes the agency's own NPS request e-mail — `template: { subject, body }`, plain text, with `{{client}}`, `{{agence}}` and `{{lien}}` substituted at send time — or `template: null` to go back to the product's copy in each reader's language.\n\nDoes what the dashboard's `saveNpsTemplateAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"template":{"anyOf":[{"type":"object","properties":{"subject":{"type":"string","minLength":1,"maxLength":150},"body":{"type":"string","minLength":1,"maxLength":2000}},"required":["subject","body"]},{"type":"null"}]}},"required":["template"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/set-record-deletion":{"post":{"operationId":"runAgencySettingsSetRecordDeletion","tags":["Agency settings"],"summary":"Allow record deletion","description":"Turns deletion of CRM records — leads, organisations, people, deals — on or off for the whole agency. This is the switch every deletion checks before it acts.\n\nDoes what the dashboard's `saveRecordDeletionAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"}},"required":["enabled"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/create-api-key":{"post":{"operationId":"runAgencySettingsCreateApiKey","tags":["Agency settings"],"summary":"Create an API key","description":"Creates an API key for the agency and returns its plaintext ONCE — only the hash is stored. `scopes` narrows what it may do; without it, the key has full access.\n\nDoes what the dashboard's `createApiKeyAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":120},"scopes":{"minItems":1,"maxItems":50,"type":"array","items":{"type":"string","pattern":"^(\\*|\\*:read|\\*:write|[a-z0-9-]+:(read|write))$"}}},"required":["name"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/revoke-api-key":{"post":{"operationId":"runAgencySettingsRevokeApiKey","tags":["Agency settings"],"summary":"Revoke an API key","description":"Permanently revokes the API key named by its display prefix. Revoking the key making the call is allowed, and takes effect immediately.\n\nDoes what the dashboard's `revokeApiKeyAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prefix":{"type":"string","minLength":4,"maxLength":20}},"required":["prefix"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/set-api-key-owner":{"post":{"operationId":"runAgencySettingsSetApiKeyOwner","tags":["Agency settings"],"summary":"Change an API key's owner","description":"Assigns the key named by its prefix to the given member (an id from `GET /v1/members`). From the next call on, the key's usage is charged to that member. A key always has an owner: detaching one would also detach it from the owner's personal cap.\n\nDoes what the dashboard's `setApiKeyOwnerAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prefix":{"type":"string","minLength":4,"maxLength":20},"ownerId":{"type":"string","minLength":1,"maxLength":120}},"required":["prefix","ownerId"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/get-api-usage":{"post":{"operationId":"runAgencySettingsGetApiUsage","tags":["Agency settings"],"summary":"API usage","description":"Returns the agency's token pool for the current cycle — allowance, spent, remaining, reset date — and how it breaks down per member. The same figures ride on every response in the `X-Quota-*` headers.\n\nDoes what the dashboard's `getApiUsageAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/resync-api-quota":{"post":{"operationId":"runAgencySettingsResyncApiQuota","tags":["Agency settings"],"summary":"Recompute the API allowance","description":"Recomputes the monthly pool from the plan and the seat count, and applies it. The caller supplies no number, so the resulting allowance never exceeds what the plan grants — and may lower one that had been raised by hand.\n\nDoes what the dashboard's `resyncApiQuotaAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/create-webhook":{"post":{"operationId":"runAgencySettingsCreateWebhook","tags":["Agency settings"],"summary":"Register a webhook","description":"Registers a public HTTPS URL that will receive every event of the domain as a signed POST, and returns its signing secret ONCE.\n\nDoes what the dashboard's `createWebhookAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","maxLength":2000,"format":"uri"}},"required":["url"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/delete-webhook":{"post":{"operationId":"runAgencySettingsDeleteWebhook","tags":["Agency settings"],"summary":"Delete a webhook","description":"Deletes the webhook or webhooks registered for the exact URL given. Deliveries stop immediately.\n\nDoes what the dashboard's `deleteWebhookAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","maxLength":2000,"format":"uri"}},"required":["url"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/toggle-role-permission":{"post":{"operationId":"runAgencySettingsToggleRolePermission","tags":["Agency settings"],"summary":"Change a role permission","description":"Grants or removes a permission (`module.action`, e.g. `tickets.delete`) on the role named by its key. The Owner role is never editable.\n\nDoes what the dashboard's `toggleRolePermissionAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"roleKey":{"type":"string","minLength":1,"maxLength":60},"permissionKey":{"type":"string"},"enabled":{"type":"boolean"}},"required":["roleKey","permissionKey","enabled"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/reset-role-to-preset":{"post":{"operationId":"runAgencySettingsResetRoleToPreset","tags":["Agency settings"],"summary":"Restore a role's preset","description":"Resets a system role's permissions (`member`, `partner`, `client_admin`, `client_member`) to their original preset, discarding the agency's adjustments.\n\nDoes what the dashboard's `resetRoleToPresetAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"roleKey":{"type":"string","minLength":1,"maxLength":60}},"required":["roleKey"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/save-connector-key":{"post":{"operationId":"runAgencySettingsSaveConnectorKey","tags":["Agency settings"],"summary":"Save a connector key","description":"Saves or replaces a marketplace connector's API key at agency level (`ahrefs`, `semrush`, `fathom_analytics`, `pennylane`, `bing_webmaster`, `tiktok_ads`). The key is encrypted and never readable again. Requires a plan with connectors (Pro and above, trials included; `pennylane` needs Scale).\n\nDoes what the dashboard's `saveConnectorKeyAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"connectorId":{"type":"string","enum":["ahrefs","semrush","fathom_analytics","pennylane","bing_webmaster","tiktok_ads"]},"apiKey":{"type":"string","minLength":10,"maxLength":500}},"required":["connectorId","apiKey"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/disconnect-connector":{"post":{"operationId":"runAgencySettingsDisconnectConnector","tags":["Agency settings"],"summary":"Disconnect a connector","description":"Deletes the agency-level credentials of a marketplace connector (`ahrefs`, `semrush`, `fathom_analytics`, `webflow`, `pennylane`, `bing_webmaster`, `tiktok_ads`, `meta_ads`, `linkedin_ads`). Per-client connections and the capture history are kept.\n\nDoes what the dashboard's `disconnectConnectorAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"connectorId":{"type":"string","enum":["ahrefs","semrush","fathom_analytics","webflow","pennylane","bing_webmaster","tiktok_ads","meta_ads","linkedin_ads"]}},"required":["connectorId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/disconnect-google-ads":{"post":{"operationId":"runAgencySettingsDisconnectGoogleAds","tags":["Agency settings"],"summary":"Disconnect Google Ads","description":"Revokes the agency's Google Ads OAuth consent — the refresh token is revoked at Google, then deleted. Per-client connections and history are kept.\n\nDoes what the dashboard's `disconnectGoogleAdsAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/disconnect-google-analytics":{"post":{"operationId":"runAgencySettingsDisconnectGoogleAnalytics","tags":["Agency settings"],"summary":"Disconnect Google Analytics","description":"Revokes the agency's Google Analytics / Search Console OAuth consent — the refresh token is revoked at Google, then deleted. Per-client connections and history are kept.\n\nDoes what the dashboard's `disconnectGoogleAnalyticsAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/disconnect-google-business":{"post":{"operationId":"runAgencySettingsDisconnectGoogleBusiness","tags":["Agency settings"],"summary":"Disconnect Google Business Profile","description":"Revokes the agency's Google Business Profile OAuth consent — its own consent, so revoking it leaves Analytics, Ads and YouTube untouched. Per-client connections and history are kept.\n\nDoes what the dashboard's `disconnectGoogleBusinessAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/disconnect-google-youtube":{"post":{"operationId":"runAgencySettingsDisconnectGoogleYoutube","tags":["Agency settings"],"summary":"Disconnect YouTube","description":"Revokes the agency's YouTube Analytics OAuth consent — its own consent, so revoking it leaves the other Google connections untouched. Per-client connections and history are kept.\n\nDoes what the dashboard's `disconnectGoogleYoutubeAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/disconnect-google-drive":{"post":{"operationId":"runAgencySettingsDisconnectGoogleDrive","tags":["Agency settings"],"summary":"Disconnect Google Drive","description":"Removes the agency's Google Drive connection, destroying the stored OAuth tokens. Folders already linked to clients stay in the database but cannot be read until Drive is reconnected.\n\nDoes what the dashboard's `disconnectDriveAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/disconnect-google-calendar":{"post":{"operationId":"runAgencySettingsDisconnectGoogleCalendar","tags":["Agency settings"],"summary":"Disconnect Google Calendar","description":"Removes the agency's Google Calendar connection, destroying the stored OAuth tokens, and empties the cached calendar. The events themselves stay at Google.\n\nDoes what the dashboard's `disconnectGoogleCalendarAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/disconnect-github":{"post":{"operationId":"runAgencySettingsDisconnectGithub","tags":["Agency settings"],"summary":"Disconnect GitHub","description":"Deletes the agency's GitHub webhook secret. Events GitHub sends are refused from then on, having no verifiable signature — the webhook should be removed on the repository side too.\n\nDoes what the dashboard's `disconnectGithubAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/generate-github-secret":{"post":{"operationId":"runAgencySettingsGenerateGithubSecret","tags":["Agency settings"],"summary":"Generate the GitHub webhook secret","description":"Mints or rotates the agency's GitHub webhook secret and returns it in plaintext ONCE, to paste into the GitHub webhook settings. The previous secret is invalidated immediately.\n\nDoes what the dashboard's `generateGithubSecretAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/disconnect-legacy-fathom":{"post":{"operationId":"runAgencySettingsDisconnectLegacyFathom","tags":["Agency settings"],"summary":"Disconnect the agency's legacy Fathom","description":"Removes the agency's legacy Fathom connection, from before per-member connections: the webhook is withdrawn at Fathom first, then the stored credentials are destroyed. Members' personal connections and already-imported notes are kept.\n\nDoes what the dashboard's `disconnectLegacyFathomAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/sync-fathom":{"post":{"operationId":"runAgencySettingsSyncFathom","tags":["Agency settings"],"summary":"Import Fathom meeting notes","description":"Re-reads the last 30 days of meeting notes from Fathom for every connection of the agency and attaches them to clients. Idempotent — an already-imported note is updated, never duplicated — and capped at 10 pages per connection, but it calls Fathom once per connection: use it to catch up on a missed webhook, not as a sync loop.\n\nDoes what the dashboard's `syncFathomAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/refresh-connect-status":{"post":{"operationId":"runAgencySettingsRefreshConnectStatus","tags":["Agency settings"],"summary":"Refresh the Stripe Connect status","description":"Re-reads the agency's Connect account at Stripe, records its capabilities — charges, payouts, details submitted — and returns them. Idempotent and free of side effects at Stripe, but the `account.updated` webhook already keeps this status current: use it to catch up, not as a polling loop.\n\nDoes what the dashboard's `refreshConnectStatusAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/disconnect-slack":{"post":{"operationId":"runAgencySettingsDisconnectSlack","tags":["Agency settings"],"summary":"Disconnect the Slack workspace","description":"Removes the link between the agency and its Slack workspace, along with the bot token stored there. Slack commands and notifications stop immediately, and reconnecting requires fresh OAuth consent.\n\nDoes what the dashboard's `disconnectSlackAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/post-slack-request-button":{"post":{"operationId":"runAgencySettingsPostSlackRequestButton","tags":["Agency settings"],"summary":"Post the \"New request\" button","description":"Posts the message carrying the \"New request\" button into a Slack channel — the only way a client reaches Dashly from a shared channel, since slash commands do not cross Slack Connect.\n\nDoes what the dashboard's `postRequestButtonAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"channel":{"type":"string","maxLength":120}},"required":["channel"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/agency-settings/actions/set-slack-notify-channel":{"post":{"operationId":"runAgencySettingsSetSlackNotifyChannel","tags":["Agency settings"],"summary":"Choose the Slack notification channel","description":"Sets the Slack channel the agency's notifications go to, after checking the bot can post there. An empty value clears the setting. This channel is shared by the whole agency and every ticket names its client in it, so pointing it at a channel shared with one client would show them the others.\n\nDoes what the dashboard's `setNotifyChannelAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `agency-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"channel":{"type":"string","maxLength":120}},"required":["channel"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/branding":{"get":{"operationId":"listBranding","tags":["Portal branding"],"summary":"List portal branding","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `branding:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["updatedAt","-updatedAt"],"default":"-updatedAt"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Branding"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/branding/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getBranding","tags":["Portal branding"],"summary":"Retrieve a portal branding","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `branding:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Branding"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/branding/actions":{"get":{"operationId":"listBrandingActions","tags":["Portal branding"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `branding:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/branding/actions/save":{"post":{"operationId":"runBrandingSave","tags":["Portal branding"],"summary":"Save the portal branding","description":"Writes the client portal's branding — logo, accent colour as `#RRGGBB`, welcome message and video. An empty string clears a field. Requires a plan with branding (Pro and above, trials included).\n\nDoes what the dashboard's `saveBrandingAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `branding:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"logoUrl":{"anyOf":[{"type":"string","maxLength":500,"format":"uri"},{"type":"string","const":""}]},"accentColor":{"anyOf":[{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},{"type":"string","const":""}]},"welcomeMessage":{"anyOf":[{"type":"string","maxLength":280},{"type":"string","const":""}]},"welcomeVideoUrl":{"anyOf":[{"type":"string","maxLength":500,"format":"uri"},{"type":"string","const":""}]}}}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/branding/actions/set-section-visibility":{"post":{"operationId":"runBrandingSetSectionVisibility","tags":["Portal branding"],"summary":"Show or hide a portal section","description":"Shows or hides a built-in portal section, on the agency's template or for one client. Hiding never removes a right and showing never grants one: the section stays subject to the client's permissions.\n\nDoes what the dashboard's `setSectionVisibilityAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `branding:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"clientId":{"anyOf":[{"type":"string","minLength":1,"maxLength":60},{"type":"null"}]},"key":{"type":"string","enum":["home","assistant","projects","tickets","suggestions","docs","sharedDocs","messages","stats","aiVisibility","reports","decks","retainer","invoices"]},"visible":{"type":"boolean"}},"required":["key","visible"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/branding/actions/rename-section":{"post":{"operationId":"runBrandingRenameSection","tags":["Portal branding"],"summary":"Rename a portal section","description":"Renames a built-in portal section, 40 characters maximum. An empty or null label restores the original name, and the section is shown again either way.\n\nDoes what the dashboard's `renameSectionAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `branding:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"clientId":{"anyOf":[{"type":"string","minLength":1,"maxLength":60},{"type":"null"}]},"key":{"type":"string","enum":["home","assistant","projects","tickets","suggestions","docs","sharedDocs","messages","stats","aiVisibility","reports","decks","retainer","invoices"]},"label":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}]}},"required":["key"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/branding/actions/remove-section":{"post":{"operationId":"runBrandingRemoveSection","tags":["Portal branding"],"summary":"Remove a section customisation","description":"Removes a section's customisation: a block disappears, and a built-in section goes back to what it inherits — the agency's template, or the product's catalogue.\n\nDoes what the dashboard's `removeSectionAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `branding:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"clientId":{"anyOf":[{"type":"string","minLength":1,"maxLength":60},{"type":"null"}]},"key":{"type":"string","minLength":1,"maxLength":80}},"required":["key"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/branding/actions/reorder-sections":{"post":{"operationId":"runBrandingReorderSections","tags":["Portal branding"],"summary":"Reorder the portal sections","description":"Sets the order of the portal's sections: each one's position is its rank in the list you send, first to last.\n\nDoes what the dashboard's `reorderSectionsAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `branding:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"clientId":{"anyOf":[{"type":"string","minLength":1,"maxLength":60},{"type":"null"}]},"ordered":{"minItems":1,"maxItems":60,"type":"array","items":{"type":"object","properties":{"key":{"type":"string","minLength":1,"maxLength":80},"type":{"type":"string","enum":["native","block"]}},"required":["key","type"]}}},"required":["ordered"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/branding/actions/reset-client-portal":{"post":{"operationId":"runBrandingResetClientPortal","tags":["Portal branding"],"summary":"Reset a client's portal","description":"Removes every customisation on this client's portal, its blocks included, so it follows the agency's template in full again.\n\nDoes what the dashboard's `resetClientPortalAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `branding:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"clientId":{"type":"string","minLength":1,"maxLength":60}},"required":["clientId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/branding/actions/save-block":{"post":{"operationId":"runBrandingSaveBlock","tags":["Portal branding"],"summary":"Save a portal block","description":"Creates or updates a portal block (`richtext`, `link`, `embed` or `file`) on the agency's template or on one client. The key returned is what edits the same block later. A file travels as base64, 5 MB maximum once decoded.\n\nDoes what the dashboard's `saveBlockAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `branding:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"clientId":{"anyOf":[{"type":"string","minLength":1,"maxLength":60},{"type":"null"}]},"key":{"type":"string","minLength":1,"maxLength":80},"label":{"type":"string","maxLength":60},"position":{"type":"integer","minimum":0,"maximum":9999},"kind":{"type":"string","const":"richtext"},"html":{"type":"string","minLength":1,"maxLength":20000}},"required":["kind","html"],"additionalProperties":false},{"type":"object","properties":{"clientId":{"anyOf":[{"type":"string","minLength":1,"maxLength":60},{"type":"null"}]},"key":{"type":"string","minLength":1,"maxLength":80},"label":{"type":"string","maxLength":60},"position":{"type":"integer","minimum":0,"maximum":9999},"kind":{"type":"string","const":"link"},"url":{"type":"string","maxLength":2000,"format":"uri"},"text":{"type":"string","maxLength":80}},"required":["kind","url"],"additionalProperties":false},{"type":"object","properties":{"clientId":{"anyOf":[{"type":"string","minLength":1,"maxLength":60},{"type":"null"}]},"key":{"type":"string","minLength":1,"maxLength":80},"label":{"type":"string","maxLength":60},"position":{"type":"integer","minimum":0,"maximum":9999},"kind":{"type":"string","const":"embed"},"url":{"type":"string","maxLength":2000,"format":"uri"}},"required":["kind","url"],"additionalProperties":false},{"type":"object","properties":{"clientId":{"anyOf":[{"type":"string","minLength":1,"maxLength":60},{"type":"null"}]},"key":{"type":"string","minLength":1,"maxLength":80},"label":{"type":"string","maxLength":60},"position":{"type":"integer","minimum":0,"maximum":9999},"kind":{"type":"string","const":"file"},"fileName":{"type":"string","minLength":1,"maxLength":200},"contentType":{"type":"string","maxLength":120},"data":{"type":"string","format":"base64","contentEncoding":"base64","pattern":"^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$"}},"required":["kind","fileName","data"],"additionalProperties":false}]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/doc-folders":{"get":{"operationId":"listDocFolders","tags":["Doc folders"],"summary":"List doc folders","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `doc-folders:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["name","-name","createdAt","-createdAt"],"default":"name"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: name.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DocFolders"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createDocFolders","tags":["Doc folders"],"summary":"Create a doc folder","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `doc-folders:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocFoldersCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/DocFolders"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/doc-folders/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getDocFolders","tags":["Doc folders"],"summary":"Retrieve a doc folder","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `doc-folders:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/DocFolders"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateDocFolders","tags":["Doc folders"],"summary":"Update a doc folder","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `doc-folders:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocFoldersUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/DocFolders"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteDocFolders","tags":["Doc folders"],"summary":"Delete a doc folder","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `doc-folders:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/doc-folders/actions":{"get":{"operationId":"listDocFoldersActions","tags":["Doc folders"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `doc-folders:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/lost-reasons":{"get":{"operationId":"listLostReasons","tags":["Lost reasons"],"summary":"List lost reasons","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `lost-reasons:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["position","-position","label","-label","createdAt","-createdAt"],"default":"position"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: label.","schema":{"type":"string"}},{"name":"filter[archived]","in":"query","description":"Exact match on `archived`.","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/LostReasons"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createLostReasons","tags":["Lost reasons"],"summary":"Create a lost reason","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `lost-reasons:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LostReasonsCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/LostReasons"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/lost-reasons/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getLostReasons","tags":["Lost reasons"],"summary":"Retrieve a lost reason","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `lost-reasons:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/LostReasons"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateLostReasons","tags":["Lost reasons"],"summary":"Update a lost reason","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `lost-reasons:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LostReasonsUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/LostReasons"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteLostReasons","tags":["Lost reasons"],"summary":"Delete a lost reason","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `lost-reasons:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/lost-reasons/actions":{"get":{"operationId":"listLostReasonsActions","tags":["Lost reasons"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `lost-reasons:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/lost-reasons/actions/move":{"post":{"operationId":"runLostReasonsMove","tags":["Lost reasons"],"summary":"Reorder a lost reason","description":"Swaps the reason with its neighbour above or below in the catalogue's order. With no neighbour that way, the order is left as it is.\n\nDoes what the dashboard's `moveLostReasonAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `lost-reasons:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reasonId":{"type":"string","minLength":1,"maxLength":60},"direction":{"type":"string","enum":["up","down"]}},"required":["reasonId","direction"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/lead-sources":{"get":{"operationId":"listLeadSources","tags":["Lead sources"],"summary":"List lead sources","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `lead-sources:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["position","-position","label","-label","createdAt","-createdAt"],"default":"position"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: label.","schema":{"type":"string"}},{"name":"filter[archived]","in":"query","description":"Exact match on `archived`.","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/LeadSources"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createLeadSources","tags":["Lead sources"],"summary":"Create a lead source","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `lead-sources:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadSourcesCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/LeadSources"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/lead-sources/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getLeadSources","tags":["Lead sources"],"summary":"Retrieve a lead source","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `lead-sources:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/LeadSources"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateLeadSources","tags":["Lead sources"],"summary":"Update a lead source","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `lead-sources:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadSourcesUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/LeadSources"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteLeadSources","tags":["Lead sources"],"summary":"Delete a lead source","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `lead-sources:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/lead-sources/actions":{"get":{"operationId":"listLeadSourcesActions","tags":["Lead sources"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `lead-sources:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/lead-sources/actions/move":{"post":{"operationId":"runLeadSourcesMove","tags":["Lead sources"],"summary":"Reorder a lead source","description":"Swaps the source with its neighbour above or below in the catalogue's order. With no neighbour that way, the order is left as it is.\n\nDoes what the dashboard's `moveLeadSourceAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `lead-sources:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sourceId":{"type":"string","minLength":1,"maxLength":60},"direction":{"type":"string","enum":["up","down"]}},"required":["sourceId","direction"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/contact-roles":{"get":{"operationId":"listContactRoles","tags":["Contact roles"],"summary":"List contact roles","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `contact-roles:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["position","-position","name","-name","createdAt","-createdAt"],"default":"position"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: name.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ContactRoles"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createContactRoles","tags":["Contact roles"],"summary":"Create a contact role","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `contact-roles:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactRolesCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ContactRoles"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/contact-roles/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getContactRoles","tags":["Contact roles"],"summary":"Retrieve a contact role","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `contact-roles:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ContactRoles"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateContactRoles","tags":["Contact roles"],"summary":"Update a contact role","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `contact-roles:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactRolesUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ContactRoles"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteContactRoles","tags":["Contact roles"],"summary":"Delete a contact role","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `contact-roles:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/contact-roles/actions":{"get":{"operationId":"listContactRolesActions","tags":["Contact roles"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `contact-roles:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/contact-roles/actions/move":{"post":{"operationId":"runContactRolesMove","tags":["Contact roles"],"summary":"Reorder a contact role","description":"Swaps the role with its neighbour above or below in the catalogue's order. With no neighbour that way, the order is left as it is.\n\nDoes what the dashboard's `moveContactRoleAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `contact-roles:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"roleId":{"type":"string","minLength":1,"maxLength":60},"direction":{"type":"string","enum":["up","down"]}},"required":["roleId","direction"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/tax-rates":{"get":{"operationId":"listTaxRates","tags":["Tax rates"],"summary":"List tax rates","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `tax-rates:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["position","-position","label","-label","rateBps","-rateBps","createdAt","-createdAt"],"default":"position"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: label.","schema":{"type":"string"}},{"name":"filter[archived]","in":"query","description":"Exact match on `archived`.","schema":{"type":"string","enum":["true","false"]}},{"name":"filter[country]","in":"query","description":"Exact match on `country`.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TaxRates"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createTaxRates","tags":["Tax rates"],"summary":"Create a tax rate","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `tax-rates:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaxRatesCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TaxRates"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/tax-rates/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getTaxRates","tags":["Tax rates"],"summary":"Retrieve a tax rate","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `tax-rates:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TaxRates"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateTaxRates","tags":["Tax rates"],"summary":"Update a tax rate","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `tax-rates:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaxRatesUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TaxRates"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteTaxRates","tags":["Tax rates"],"summary":"Delete a tax rate","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `tax-rates:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/tax-rates/actions":{"get":{"operationId":"listTaxRatesActions","tags":["Tax rates"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `tax-rates:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/tax-rates/actions/set-default":{"post":{"operationId":"runTaxRatesSetDefault","tags":["Tax rates"],"summary":"Set the default tax rate","description":"Names the rate applied to any line that does not specify one. Whichever rate held the title loses it in the same transaction — an agency always has exactly one default.\n\nDoes what the dashboard's `setDefaultTaxRateAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `tax-rates:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rateId":{"type":"string","minLength":1,"maxLength":60}},"required":["rateId"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deal-products":{"get":{"operationId":"listDealProducts","tags":["Deal products"],"summary":"List deal products","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `deal-products:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["position","-position","createdAt","-createdAt"],"default":"position"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: name.","schema":{"type":"string"}},{"name":"filter[dealId]","in":"query","description":"Exact match on `dealId`.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DealProducts"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deal-products/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getDealProducts","tags":["Deal products"],"summary":"Retrieve a deal product","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `deal-products:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/DealProducts"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deal-products/actions":{"get":{"operationId":"listDealProductsActions","tags":["Deal products"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `deal-products:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/products":{"get":{"operationId":"listProducts","tags":["Products"],"summary":"List products","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `products:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["name","-name","createdAt","-createdAt","unitAmountCents","-unitAmountCents"],"default":"name"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: name, description.","schema":{"type":"string"}},{"name":"filter[kind]","in":"query","description":"Exact match on `kind`.","schema":{"type":"string","enum":["one_shot","recurring"]}},{"name":"filter[active]","in":"query","description":"Exact match on `active`.","schema":{"type":"string","enum":["true","false"]}},{"name":"filter[currency]","in":"query","description":"Exact match on `currency`.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Products"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createProducts","tags":["Products"],"summary":"Create a product","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `products:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductsCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Products"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/products/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getProducts","tags":["Products"],"summary":"Retrieve a product","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `products:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Products"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateProducts","tags":["Products"],"summary":"Update a product","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `products:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductsUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Products"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteProducts","tags":["Products"],"summary":"Delete a product","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `products:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/products/actions":{"get":{"operationId":"listProductsActions","tags":["Products"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `products:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/product-categories":{"get":{"operationId":"listProductCategories","tags":["Product categories"],"summary":"List product categories","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `product-categories:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["position","-position","label","-label","createdAt","-createdAt"],"default":"position"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: label.","schema":{"type":"string"}},{"name":"filter[archived]","in":"query","description":"Exact match on `archived`.","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ProductCategories"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createProductCategories","tags":["Product categories"],"summary":"Create a product category","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `product-categories:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductCategoriesCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ProductCategories"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/product-categories/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getProductCategories","tags":["Product categories"],"summary":"Retrieve a product category","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `product-categories:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ProductCategories"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateProductCategories","tags":["Product categories"],"summary":"Update a product category","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `product-categories:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductCategoriesUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ProductCategories"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteProductCategories","tags":["Product categories"],"summary":"Delete a product category","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `product-categories:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/product-categories/actions":{"get":{"operationId":"listProductCategoriesActions","tags":["Product categories"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `product-categories:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/product-packages":{"get":{"operationId":"listProductPackages","tags":["Product packages"],"summary":"List product packages","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `product-packages:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["name","-name","createdAt","-createdAt"],"default":"name"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: name, description.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ProductPackages"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createProductPackages","tags":["Product packages"],"summary":"Create a product package","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `product-packages:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductPackagesCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ProductPackages"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/product-packages/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getProductPackages","tags":["Product packages"],"summary":"Retrieve a product package","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `product-packages:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ProductPackages"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateProductPackages","tags":["Product packages"],"summary":"Update a product package","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `product-packages:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductPackagesUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ProductPackages"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteProductPackages","tags":["Product packages"],"summary":"Delete a product package","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `product-packages:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/product-packages/actions":{"get":{"operationId":"listProductPackagesActions","tags":["Product packages"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `product-packages:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/product-packages/actions/create-with-items":{"post":{"operationId":"runProductPackagesCreateWithItems","tags":["Product packages"],"summary":"Create a package with its lines","description":"Creates a package and its priced lines in one call: name, description, and lines — a catalogue product by its public id, quantity, unit price in cents, discount and tax rate.\n\nDoes what the dashboard's `createPackageAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `product-packages:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"description":{"default":"","type":"string","maxLength":2000},"items":{"default":[],"maxItems":100,"type":"array","items":{"type":"object","properties":{"productId":{"anyOf":[{"type":"string","minLength":1,"maxLength":60},{"type":"null"}]},"name":{"default":"","type":"string","maxLength":200},"quantity":{"default":1,"type":"number","minimum":0,"maximum":100000},"unitAmountCents":{"default":0,"type":"integer","minimum":0,"maximum":9007199254740991},"discountPct":{"default":0,"type":"number","minimum":0,"maximum":100},"taxRatePct":{"default":0,"type":"number","minimum":0,"maximum":100}}}}},"required":["name"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/ticket-templates":{"get":{"operationId":"listTicketTemplates","tags":["Ticket templates"],"summary":"List ticket templates","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `ticket-templates:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt","name","-name"],"default":"-createdAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: name, title.","schema":{"type":"string"}},{"name":"filter[scope]","in":"query","description":"Exact match on `scope`.","schema":{"type":"string","enum":["client","agency","internal"]}},{"name":"filter[priority]","in":"query","description":"Exact match on `priority`.","schema":{"type":"string","enum":["low","medium","high","urgent"]}},{"name":"filter[clientVisible]","in":"query","description":"Exact match on `clientVisible`.","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TicketTemplates"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createTicketTemplates","tags":["Ticket templates"],"summary":"Create a ticket template","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `ticket-templates:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketTemplatesCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TicketTemplates"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/ticket-templates/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getTicketTemplates","tags":["Ticket templates"],"summary":"Retrieve a ticket template","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `ticket-templates:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TicketTemplates"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateTicketTemplates","tags":["Ticket templates"],"summary":"Update a ticket template","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `ticket-templates:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketTemplatesUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TicketTemplates"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteTicketTemplates","tags":["Ticket templates"],"summary":"Delete a ticket template","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `ticket-templates:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/ticket-templates/actions":{"get":{"operationId":"listTicketTemplatesActions","tags":["Ticket templates"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `ticket-templates:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/ticket-templates/{id}/actions/instantiate":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runTicketTemplatesInstantiate","tags":["Ticket templates"],"summary":"Create a ticket from this template","description":"Turns the template into a new ticket, copying title, description, scope, priority, category, client visibility and custom fields. `clientId` attaches it to a client.\n\nDoes what the dashboard's `createTicketFromTemplateAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `ticket-templates:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"clientId":{"type":"string","minLength":1,"maxLength":60}},"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/recurring-tickets":{"get":{"operationId":"listRecurringTickets","tags":["Recurring tickets"],"summary":"List recurring tickets","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `recurring-tickets:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["nextRunAt","-nextRunAt","createdAt","-createdAt"],"default":"nextRunAt"}},{"name":"filter[active]","in":"query","description":"Exact match on `active`.","schema":{"type":"string","enum":["true","false"]}},{"name":"filter[intervalUnit]","in":"query","description":"Exact match on `intervalUnit`.","schema":{"type":"string","enum":["day","week","month"]}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/RecurringTickets"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createRecurringTickets","tags":["Recurring tickets"],"summary":"Create a recurring ticket","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `recurring-tickets:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecurringTicketsCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/RecurringTickets"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/recurring-tickets/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getRecurringTickets","tags":["Recurring tickets"],"summary":"Retrieve a recurring ticket","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `recurring-tickets:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/RecurringTickets"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateRecurringTickets","tags":["Recurring tickets"],"summary":"Update a recurring ticket","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `recurring-tickets:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecurringTicketsUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/RecurringTickets"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteRecurringTickets","tags":["Recurring tickets"],"summary":"Delete a recurring ticket","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `recurring-tickets:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/recurring-tickets/actions":{"get":{"operationId":"listRecurringTicketsActions","tags":["Recurring tickets"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `recurring-tickets:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/project-templates":{"get":{"operationId":"listProjectTemplates","tags":["Project templates"],"summary":"List project templates","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `project-templates:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt","name","-name"],"default":"-createdAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: name.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ProjectTemplates"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createProjectTemplates","tags":["Project templates"],"summary":"Create a project template","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `project-templates:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectTemplatesCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ProjectTemplates"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/project-templates/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getProjectTemplates","tags":["Project templates"],"summary":"Retrieve a project template","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `project-templates:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ProjectTemplates"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateProjectTemplates","tags":["Project templates"],"summary":"Update a project template","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `project-templates:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectTemplatesUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ProjectTemplates"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteProjectTemplates","tags":["Project templates"],"summary":"Delete a project template","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `project-templates:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/project-templates/actions":{"get":{"operationId":"listProjectTemplatesActions","tags":["Project templates"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `project-templates:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/project-templates/{id}/actions/instantiate":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runProjectTemplatesInstantiate","tags":["Project templates"],"summary":"Create a project from this template","description":"Creates a project called `name` — attached to `clientId` when given — plus one ticket per template item. The project type (client onboarding) stays dashboard-only: the client notifications do not exist on the API side yet.\n\nDoes what the dashboard's `createProjectFromTemplateAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `project-templates:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":120},"clientId":{"type":"string","minLength":1,"maxLength":60}},"required":["name"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/project-templates/{id}/actions/add-item":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runProjectTemplatesAddItem","tags":["Project templates"],"summary":"Add an item to the template","description":"Appends a template ticket to the template — title, scope, priority, category by its public id, client visibility — and returns its position.\n\nDoes what the dashboard's `addProjectTemplateItemAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `project-templates:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":2,"maxLength":160},"scope":{"default":"client","type":"string","enum":["client","agency","internal"]},"priority":{"default":"medium","type":"string","enum":["low","medium","high","urgent"]},"categoryId":{"type":"string","minLength":1,"maxLength":60},"clientVisible":{"default":false,"type":"boolean"}},"required":["title"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/project-templates/{id}/actions/remove-item":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runProjectTemplatesRemoveItem","tags":["Project templates"],"summary":"Remove an item from the template","description":"Removes the template ticket with exactly this title — the first in template order when several share it. Items carry no public id, so the title is their address. Projects already created from the template keep their tickets.\n\nDoes what the dashboard's `deleteProjectTemplateItemAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `project-templates:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":160}},"required":["title"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/ticket-automations":{"get":{"operationId":"listTicketAutomations","tags":["Ticket automations"],"summary":"List ticket automations","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `ticket-automations:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["position","-position","createdAt","-createdAt","name","-name"],"default":"position"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: name.","schema":{"type":"string"}},{"name":"filter[trigger]","in":"query","description":"Exact match on `trigger`.","schema":{"type":"string"}},{"name":"filter[active]","in":"query","description":"Exact match on `active`.","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TicketAutomations"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/ticket-automations/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getTicketAutomations","tags":["Ticket automations"],"summary":"Retrieve a ticket automation","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `ticket-automations:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TicketAutomations"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/ticket-automations/actions":{"get":{"operationId":"listTicketAutomationsActions","tags":["Ticket automations"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `ticket-automations:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/ticket-automations/actions/create":{"post":{"operationId":"runTicketAutomationsCreate","tags":["Ticket automations"],"summary":"Create an automation rule","description":"Creates a \"when X then Y\" rule on tickets: a trigger, conditions (category values by public id) and actions (category and template by public id). 50 rules maximum per agency.\n\nDoes what the dashboard's `createAutomationAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `ticket-automations:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80},"trigger":{"type":"string","enum":["ticket.created","ticket.status_changed","ticket.assigned","ticket.priority_changed","ticket.comment_added","ticket.custom_field_changed","ticket.due_date_passed","github.pr_merged"]},"conditions":{"default":[],"maxItems":10,"type":"array","items":{"anyOf":[{"type":"object","properties":{"field":{"type":"string"},"op":{"type":"string","enum":["eq","neq","in","is_empty","is_not_empty"]},"value":{"anyOf":[{"type":"string","maxLength":200},{"maxItems":20,"type":"array","items":{"type":"string","maxLength":200}}]}},"required":["field","op"]},{"type":"object","properties":{"any":{"minItems":1,"maxItems":10,"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"op":{"type":"string","enum":["eq","neq","in","is_empty","is_not_empty"]},"value":{"anyOf":[{"type":"string","maxLength":200},{"maxItems":20,"type":"array","items":{"type":"string","maxLength":200}}]}},"required":["field","op"]}}},"required":["any"]}]}},"actions":{"minItems":1,"maxItems":5,"type":"array","items":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"set_status"},"status":{"type":"string","minLength":1,"maxLength":40}},"required":["type","status"]},{"type":"object","properties":{"type":{"type":"string","const":"set_priority"},"priority":{"type":"string","enum":["low","medium","high","urgent"]}},"required":["type","priority"]},{"type":"object","properties":{"type":{"type":"string","const":"set_category"},"categoryId":{"type":"string","minLength":1,"maxLength":60}},"required":["type","categoryId"]},{"type":"object","properties":{"type":{"type":"string","const":"assign"},"assigneeUserId":{"type":"string","minLength":1,"maxLength":64}},"required":["type","assigneeUserId"]},{"type":"object","properties":{"type":{"type":"string","const":"set_due_date"},"inDays":{"type":"integer","minimum":0,"maximum":365}},"required":["type","inDays"]},{"type":"object","properties":{"type":{"type":"string","const":"add_comment"},"body":{"type":"string","minLength":1,"maxLength":2000}},"required":["type","body"]},{"type":"object","properties":{"type":{"type":"string","const":"create_ticket"},"templateId":{"type":"string","minLength":1,"maxLength":60},"asSubtask":{"default":false,"type":"boolean"}},"required":["type","templateId"]},{"type":"object","properties":{"type":{"type":"string","const":"notify"},"target":{"type":"string","enum":["agency_bell","slack"]},"message":{"type":"string","minLength":1,"maxLength":300}},"required":["type","target","message"]}]}},"active":{"default":true,"type":"boolean"}},"required":["name","trigger","actions"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/ticket-automations/{id}/actions/update":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runTicketAutomationsUpdate","tags":["Ticket automations"],"summary":"Replace an automation rule","description":"Replaces the rule wholesale — name, trigger, conditions, actions, enabled state. The same contract as creation, exactly as in the dashboard.\n\nDoes what the dashboard's `updateAutomationAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `ticket-automations:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80},"trigger":{"type":"string","enum":["ticket.created","ticket.status_changed","ticket.assigned","ticket.priority_changed","ticket.comment_added","ticket.custom_field_changed","ticket.due_date_passed","github.pr_merged"]},"conditions":{"default":[],"maxItems":10,"type":"array","items":{"anyOf":[{"type":"object","properties":{"field":{"type":"string"},"op":{"type":"string","enum":["eq","neq","in","is_empty","is_not_empty"]},"value":{"anyOf":[{"type":"string","maxLength":200},{"maxItems":20,"type":"array","items":{"type":"string","maxLength":200}}]}},"required":["field","op"]},{"type":"object","properties":{"any":{"minItems":1,"maxItems":10,"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"op":{"type":"string","enum":["eq","neq","in","is_empty","is_not_empty"]},"value":{"anyOf":[{"type":"string","maxLength":200},{"maxItems":20,"type":"array","items":{"type":"string","maxLength":200}}]}},"required":["field","op"]}}},"required":["any"]}]}},"actions":{"minItems":1,"maxItems":5,"type":"array","items":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"set_status"},"status":{"type":"string","minLength":1,"maxLength":40}},"required":["type","status"]},{"type":"object","properties":{"type":{"type":"string","const":"set_priority"},"priority":{"type":"string","enum":["low","medium","high","urgent"]}},"required":["type","priority"]},{"type":"object","properties":{"type":{"type":"string","const":"set_category"},"categoryId":{"type":"string","minLength":1,"maxLength":60}},"required":["type","categoryId"]},{"type":"object","properties":{"type":{"type":"string","const":"assign"},"assigneeUserId":{"type":"string","minLength":1,"maxLength":64}},"required":["type","assigneeUserId"]},{"type":"object","properties":{"type":{"type":"string","const":"set_due_date"},"inDays":{"type":"integer","minimum":0,"maximum":365}},"required":["type","inDays"]},{"type":"object","properties":{"type":{"type":"string","const":"add_comment"},"body":{"type":"string","minLength":1,"maxLength":2000}},"required":["type","body"]},{"type":"object","properties":{"type":{"type":"string","const":"create_ticket"},"templateId":{"type":"string","minLength":1,"maxLength":60},"asSubtask":{"default":false,"type":"boolean"}},"required":["type","templateId"]},{"type":"object","properties":{"type":{"type":"string","const":"notify"},"target":{"type":"string","enum":["agency_bell","slack"]},"message":{"type":"string","minLength":1,"maxLength":300}},"required":["type","target","message"]}]}},"active":{"default":true,"type":"boolean"}},"required":["name","trigger","actions"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/ticket-automations/{id}/actions/toggle":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runTicketAutomationsToggle","tags":["Ticket automations"],"summary":"Enable or pause the rule","description":"Enables (`active: true`) or pauses (`active: false`) the rule without otherwise changing it.\n\nDoes what the dashboard's `toggleAutomationAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `ticket-automations:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"active":{"type":"boolean"}},"required":["active"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/ticket-automations/{id}/actions/delete":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runTicketAutomationsDelete","tags":["Ticket automations"],"summary":"Delete the rule","description":"Permanently deletes the rule and its run log. The collection is read-only, so deletion goes through this verb.\n\nDoes what the dashboard's `deleteAutomationAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `ticket-automations:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/ticket-automations/actions/create-draft":{"post":{"operationId":"runTicketAutomationsCreateDraft","tags":["Ticket automations"],"summary":"Create a blank rule","description":"Creates an inactive rule called \"Nouvelle règle\", triggered when a ticket is created and setting the first column of the agency's workflow. Returns its id so you can configure it next. 50 rules maximum per agency.\n\nDoes what the dashboard's `createDraftAutomationAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `ticket-automations:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/ticket-automations/{id}/actions/set-tags":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runTicketAutomationsSetTags","tags":["Ticket automations"],"summary":"Set a rule's tags","description":"Replaces the rule's tags with exactly this list (ids from `/v1/automation-tags`). An empty list removes them all.\n\nDoes what the dashboard's `setRuleTagsAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `ticket-automations:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tagIds":{"maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":60}}},"required":["tagIds"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/automation-tags":{"get":{"operationId":"listAutomationTags","tags":["Automation tags"],"summary":"List automation tags","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `automation-tags:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["name","-name","createdAt","-createdAt"],"default":"name"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: name.","schema":{"type":"string"}},{"name":"filter[color]","in":"query","description":"Exact match on `color`.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AutomationTags"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/automation-tags/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getAutomationTags","tags":["Automation tags"],"summary":"Retrieve a automation tag","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `automation-tags:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AutomationTags"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/automation-tags/actions":{"get":{"operationId":"listAutomationTagsActions","tags":["Automation tags"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `automation-tags:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/automation-tags/actions/create":{"post":{"operationId":"runAutomationTagsCreate","tags":["Automation tags"],"summary":"Create a rule tag","description":"Creates a tag: a name plus a colour from the palette (slate, brand, emerald, amber, rose, violet, sky). A name already taken, case-insensitively, returns the existing tag. 20 tags maximum per agency.\n\nDoes what the dashboard's `createTagAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `automation-tags:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":30},"color":{"type":"string"}},"required":["name","color"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/automation-tags/{id}/actions/update":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runAutomationTagsUpdate","tags":["Automation tags"],"summary":"Rename or recolour a tag","description":"Changes the tag's name, its colour, or both. Rules carrying it keep it.\n\nDoes what the dashboard's `updateTagAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `automation-tags:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":30},"color":{"type":"string"}},"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/automation-tags/{id}/actions/delete":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runAutomationTagsDelete","tags":["Automation tags"],"summary":"Delete a tag","description":"Deletes the tag and strips it from every rule that carried it. The rules themselves stay.\n\nDoes what the dashboard's `deleteTagAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `automation-tags:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/project-types":{"get":{"operationId":"listProjectTypes","tags":["Project types"],"summary":"List project types","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `project-types:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["position","-position","createdAt","-createdAt","name","-name"],"default":"position"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: name.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ProjectTypes"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createProjectTypes","tags":["Project types"],"summary":"Create a project type","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `project-types:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectTypesCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ProjectTypes"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/project-types/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getProjectTypes","tags":["Project types"],"summary":"Retrieve a project type","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `project-types:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ProjectTypes"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateProjectTypes","tags":["Project types"],"summary":"Update a project type","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `project-types:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectTypesUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ProjectTypes"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteProjectTypes","tags":["Project types"],"summary":"Delete a project type","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `project-types:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/project-types/actions":{"get":{"operationId":"listProjectTypesActions","tags":["Project types"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `project-types:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/project-types/{id}/actions/add-step":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runProjectTypesAddStep","tags":["Project types"],"summary":"Add a step to the onboarding template","description":"Appends a step to this project type's template: `form` (with `fields`), `confirm` (with `noteEnabled`), `upload` (with `accept`) or `acknowledge` (with `content`). Returns the step's id — see `/v1/onboarding-template-steps`.\n\nDoes what the dashboard's `addTemplateStepAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `project-types:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["form","confirm","upload","acknowledge"]},"title":{"type":"string","minLength":2,"maxLength":160},"description":{"type":"string","maxLength":2000},"required":{"default":true,"type":"boolean"},"noteEnabled":{"type":"boolean"},"accept":{"type":"string","maxLength":200},"content":{"type":"string","maxLength":4000},"fields":{"maxItems":50,"type":"array","items":{"type":"object","properties":{"key":{"type":"string","minLength":1,"maxLength":60,"pattern":"^[a-z0-9_]+$"},"label":{"type":"string","minLength":1,"maxLength":120},"type":{"type":"string","enum":["text","long_text","number","date","select","url","email"]},"required":{"default":false,"type":"boolean"},"options":{"type":"array","items":{"type":"string","minLength":1,"maxLength":60}}},"required":["key","label","type"]}}},"required":["kind","title"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/project-types/actions/seed-default":{"post":{"operationId":"runProjectTypesSeedDefault","tags":["Project types"],"summary":"Create the default \"Website\" type","description":"Creates the \"Site web\" project type and its default onboarding steps. Idempotent: if a type with that name already exists, nothing changes.\n\nDoes what the dashboard's `seedDefaultProjectTypeAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `project-types:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/onboarding-template-steps":{"get":{"operationId":"listOnboardingTemplateSteps","tags":["Onboarding template steps"],"summary":"List onboarding template steps","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `onboarding-template-steps:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["position","-position","createdAt","-createdAt"],"default":"position"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: title.","schema":{"type":"string"}},{"name":"filter[kind]","in":"query","description":"Exact match on `kind`.","schema":{"type":"string","enum":["form","confirm","upload","acknowledge"]}},{"name":"filter[required]","in":"query","description":"Exact match on `required`.","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OnboardingTemplateSteps"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/onboarding-template-steps/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getOnboardingTemplateSteps","tags":["Onboarding template steps"],"summary":"Retrieve a onboarding template step","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `onboarding-template-steps:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OnboardingTemplateSteps"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/onboarding-template-steps/actions":{"get":{"operationId":"listOnboardingTemplateStepsActions","tags":["Onboarding template steps"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `onboarding-template-steps:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/onboarding-template-steps/{id}/actions/move":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runOnboardingTemplateStepsMove","tags":["Onboarding template steps"],"summary":"Move the step","description":"Swaps the step with the one above (`up`) or below (`down`) within its project type. No effect at either end of the list.\n\nDoes what the dashboard's `moveTemplateStepAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `onboarding-template-steps:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"direction":{"type":"string","enum":["up","down"]}},"required":["direction"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/onboarding-template-steps/{id}/actions/delete":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runOnboardingTemplateStepsDelete","tags":["Onboarding template steps"],"summary":"Delete the step","description":"Deletes the step from the template. The collection is read-only, so deletion goes through this verb. Onboardings already created keep their copy.\n\nDoes what the dashboard's `deleteTemplateStepAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `onboarding-template-steps:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/billing-documents":{"get":{"operationId":"listBillingDocuments","tags":["Billing documents"],"summary":"List billing documents","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `billing-documents:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt","issuedAt","-issuedAt","label","-label","amountCents","-amountCents"],"default":"-createdAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: label, fileName.","schema":{"type":"string"}},{"name":"filter[kind]","in":"query","description":"Exact match on `kind`.","schema":{"type":"string","enum":["invoice","quote","other"]}},{"name":"filter[currency]","in":"query","description":"Exact match on `currency`.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BillingDocuments"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/billing-documents/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getBillingDocuments","tags":["Billing documents"],"summary":"Retrieve a billing document","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `billing-documents:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BillingDocuments"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/billing-documents/actions":{"get":{"operationId":"listBillingDocumentsActions","tags":["Billing documents"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `billing-documents:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/billing-documents/{id}/actions/share-url":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runBillingDocumentsShareUrl","tags":["Billing documents"],"summary":"Get a sharing link","description":"Returns a long-lived signed URL to the billing document's file — 180 days by default — usable on a public page, such as a proposal's Documents block.\n\nDoes what the dashboard's `billingDocShareUrlAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `billing-documents:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"expiresInSeconds":{"default":15552000,"type":"integer","minimum":60,"maximum":15552000}},"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/domains":{"get":{"operationId":"listDomains","tags":["Domains"],"summary":"List domains","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `domains:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt","domain","-domain"],"default":"-createdAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: domain.","schema":{"type":"string"}},{"name":"filter[verified]","in":"query","description":"Exact match on `verified`.","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Domains"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/domains/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getDomains","tags":["Domains"],"summary":"Retrieve a domain","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `domains:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Domains"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/domains/actions":{"get":{"operationId":"listDomainsActions","tags":["Domains"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `domains:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/domains/actions/add":{"post":{"operationId":"runDomainsAdd","tags":["Domains"],"summary":"Add a domain","description":"Declares an e-mail domain so sign-ups attach themselves to a client automatically, and returns the TXT record to publish before running the verification.\n\nDoes what the dashboard's `addDomainAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `domains:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"clientId":{"type":"string","minLength":1},"domain":{"type":"string","maxLength":253,"pattern":"^(?!-)[a-z0-9-]{1,63}(\\.[a-z0-9-]{1,63})+$"}},"required":["clientId","domain"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/domains/{id}/actions/verify":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDomainsVerify","tags":["Domains"],"summary":"Verify the domain","description":"Checks the domain's DNS for the verification TXT record and marks it verified when the token is found.\n\nDoes what the dashboard's `verifyDomainAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `domains:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/blog-posts":{"get":{"operationId":"listBlogPosts","tags":["Blog posts"],"summary":"List blog posts","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `blog-posts:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt","publishedAt","-publishedAt","updatedAt","-updatedAt","title","-title"],"default":"-createdAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: title, excerpt.","schema":{"type":"string"}},{"name":"filter[status]","in":"query","description":"Exact match on `status`.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BlogPosts"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/blog-posts/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getBlogPosts","tags":["Blog posts"],"summary":"Retrieve a blog post","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `blog-posts:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BlogPosts"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/blog-posts/actions":{"get":{"operationId":"listBlogPostsActions","tags":["Blog posts"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `blog-posts:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/blog-posts/actions/create":{"post":{"operationId":"runBlogPostsCreate","tags":["Blog posts"],"summary":"Create a post","description":"Creates a draft blog post from a title. Returns the post's public id, plus the slug derived from the title with a random suffix — the slug is what the published page is served at, and it changes when the title does.\n\nDoes what the dashboard's `createPostAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `blog-posts:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":160}},"required":["title"]}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/blog-posts/{id}/actions/update":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runBlogPostsUpdate","tags":["Blog posts"],"summary":"Update the post","description":"Updates the title, excerpt, cover image, content blocks, status or slug. The publication date is stamped the first time it is published.\n\nDoes what the dashboard's `updatePostAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `blog-posts:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":160},"excerpt":{"anyOf":[{"type":"string","maxLength":400},{"type":"null"}]},"coverImageUrl":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]},"blocks":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"status":{"type":"string","enum":["draft","published"]},"slug":{"type":"string","minLength":1,"maxLength":80}}}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/blog-posts/{id}/actions/delete":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runBlogPostsDelete","tags":["Blog posts"],"summary":"Delete the post","description":"Permanently deletes the blog post.\n\nDoes what the dashboard's `deletePostAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `blog-posts:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/partners":{"get":{"operationId":"listPartners","tags":["Partners"],"summary":"List partners","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `partners:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt","clientName","-clientName","tier","-tier"],"default":"-createdAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: clientName, contactName.","schema":{"type":"string"}},{"name":"filter[kind]","in":"query","description":"Exact match on `kind`.","schema":{"type":"string","enum":["agency","freelance","referrer","consultant"]}},{"name":"filter[status]","in":"query","description":"Exact match on `status`.","schema":{"type":"string"}},{"name":"filter[tier]","in":"query","description":"Exact match on `tier`.","schema":{"type":"string"}},{"name":"filter[clientId]","in":"query","description":"Exact match on `clientId`.","schema":{"type":"string"}},{"name":"filter[contactId]","in":"query","description":"Exact match on `contactId`.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Partners"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createPartners","tags":["Partners"],"summary":"Create a partner","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `partners:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnersCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Partners"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/partners/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getPartners","tags":["Partners"],"summary":"Retrieve a partner","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `partners:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Partners"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updatePartners","tags":["Partners"],"summary":"Update a partner","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `partners:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnersUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Partners"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/partners/actions":{"get":{"operationId":"listPartnersActions","tags":["Partners"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `partners:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/partners/{id}/actions/invite-member":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runPartnersInviteMember","tags":["Partners"],"summary":"Invite someone at this partner","description":"Sends an invitation to this address to join the partner workspace. Re-inviting the same person renews the link instead of failing.\n\nDoes what the dashboard's `invitePartnerMemberAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `partners:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","maxLength":200,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"name":{"type":"string","maxLength":120}},"required":["email"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/partners/{id}/actions/revoke-member":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runPartnersRevokeMember","tags":["Partners"],"summary":"Revoke someone","description":"Removes this person's access to the partner workspace and cancels their invitation link. The partnership itself is kept.\n\nDoes what the dashboard's `revokePartnerMemberAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `partners:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","maxLength":200,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"}},"required":["email"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/partners/actions/invite-agency":{"post":{"operationId":"runPartnersInviteAgency","tags":["Partners"],"summary":"Invite a partner agency","description":"Sends this address an invitation to link their agency to yours. The acceptance link goes out by e-mail and is never returned in the response.\n\nDoes what the dashboard's `invitePartnerAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `partners:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","maxLength":200,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"}},"required":["email"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/partners/actions/revoke-agency-invitation":{"post":{"operationId":"runPartnersRevokeAgencyInvitation","tags":["Partners"],"summary":"Cancel an agency invitation","description":"Cancels the pending invitation sent to this address. The invitation is addressed by e-mail, having no public id of its own.\n\nDoes what the dashboard's `revokePartnerInvitationAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `partners:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","maxLength":200,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"}},"required":["email"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/partners/actions/share-client-projects":{"post":{"operationId":"runPartnersShareClientProjects","tags":["Partners"],"summary":"Share all of a client's projects","description":"Shares every existing project of this client with this linked partner agency, and reports how many were added and how many already were. Projects created afterwards are not included.\n\nDoes what the dashboard's `shareAllAccountProjectsAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `partners:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"clientId":{"type":"string","minLength":1,"maxLength":60},"partnerAgencyId":{"type":"string","minLength":1,"maxLength":120}},"required":["clientId","partnerAgencyId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deal-partners":{"get":{"operationId":"listDealPartners","tags":["Deal partners"],"summary":"List deal partners","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `deal-partners:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt","sharedAt","-sharedAt"],"default":"createdAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: dealName.","schema":{"type":"string"}},{"name":"filter[dealId]","in":"query","description":"Exact match on `dealId`.","schema":{"type":"string"}},{"name":"filter[partnerId]","in":"query","description":"Exact match on `partnerId`.","schema":{"type":"string"}},{"name":"filter[role]","in":"query","description":"Exact match on `role`.","schema":{"type":"string","enum":["referrer","subcontractor","reseller"]}},{"name":"filter[billingMode]","in":"query","description":"Exact match on `billingMode`.","schema":{"type":"string","enum":["we_invoice","partner_invoices"]}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DealPartners"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createDealPartners","tags":["Deal partners"],"summary":"Create a deal partner","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `deal-partners:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DealPartnersCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/DealPartners"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deal-partners/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getDealPartners","tags":["Deal partners"],"summary":"Retrieve a deal partner","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `deal-partners:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/DealPartners"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateDealPartners","tags":["Deal partners"],"summary":"Update a deal partner","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `deal-partners:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DealPartnersUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/DealPartners"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteDealPartners","tags":["Deal partners"],"summary":"Delete a deal partner","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `deal-partners:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deal-partners/actions":{"get":{"operationId":"listDealPartnersActions","tags":["Deal partners"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `deal-partners:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deal-partners/{id}/actions/share":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDealPartnersShare","tags":["Deal partners"],"summary":"Open the deal to the partner","description":"Opens the deal to the partner — stamping `sharedAt` — and notifies their team. `email` additionally invites that address, naming the deal in the invitation. Calling again does not notify again.\n\nDoes what the dashboard's `sharePartnerDealAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `deal-partners:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","maxLength":200,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"name":{"type":"string","maxLength":120}},"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deal-partners/{id}/actions/unshare":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDealPartnersUnshare","tags":["Deal partners"],"summary":"Close the deal to the partner","description":"Removes the partner's access to the deal and tells them. Their terms — role, commission — are kept.\n\nDoes what the dashboard's `unsharePartnerDealAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `deal-partners:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deal-partners/{id}/actions/set-shared-fields":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDealPartnersSetSharedFields","tags":["Deal partners"],"summary":"Set what the partner sees","description":"Replaces the list of fields this partner can see on this deal. Any key you leave out is hidden, and the partner is notified when the deal is already open to them.\n\nDoes what the dashboard's `setSharedFieldsAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `deal-partners:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fields":{"type":"array","items":{"type":"string","enum":["deal.name","deal.stage","deal.value","deal.agency_share","deal.expected_close","deal.notes","partner.share","partner.commission","account.name","account.contacts","documents","activity"]}}},"required":["fields"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/deal-partners/{id}/actions/contact-state":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runDealPartnersContactState","tags":["Deal partners"],"summary":"Who is reachable at this partner","description":"Returns the people already invited or active at this partner, plus the address suggested for inviting a new one — null when that address is already on the list.\n\nDoes what the dashboard's `getPartnerContactStateAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `deal-partners:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/suggestions":{"get":{"operationId":"listSuggestions","tags":["Suggestions"],"summary":"List suggestions","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `suggestions:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt","status","-status","title","-title"],"default":"-createdAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: title, description.","schema":{"type":"string"}},{"name":"filter[status]","in":"query","description":"Exact match on `status`.","schema":{"type":"string"}},{"name":"filter[clientId]","in":"query","description":"Exact match on `clientId`.","schema":{"type":"string"}},{"name":"filter[projectId]","in":"query","description":"Exact match on `projectId`.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Suggestions"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/suggestions/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getSuggestions","tags":["Suggestions"],"summary":"Retrieve a suggestion","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `suggestions:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Suggestions"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/suggestions/actions":{"get":{"operationId":"listSuggestionsActions","tags":["Suggestions"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `suggestions:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/suggestions/{id}/actions/withdraw":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runSuggestionsWithdraw","tags":["Suggestions"],"summary":"Withdraw a suggestion","description":"Withdraws this suggestion from the client's portal while it is still `proposed`. One already accepted, declined or withdrawn is refused.\n\nDoes what the dashboard's `withdrawSuggestionAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `suggestions:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/geo-settings":{"get":{"operationId":"listGeoSettings","tags":["AI visibility settings"],"summary":"List ai visibility settings","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `geo-settings:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt","updatedAt","-updatedAt","brand","-brand"],"default":"-createdAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: brand, domain.","schema":{"type":"string"}},{"name":"filter[enabled]","in":"query","description":"Exact match on `enabled`.","schema":{"type":"string","enum":["true","false"]}},{"name":"filter[frequency]","in":"query","description":"Exact match on `frequency`.","schema":{"type":"string"}},{"name":"filter[country]","in":"query","description":"Exact match on `country`.","schema":{"type":"string"}},{"name":"filter[locale]","in":"query","description":"Exact match on `locale`.","schema":{"type":"string"}},{"name":"filter[portalVisible]","in":"query","description":"Exact match on `portalVisible`.","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GeoSettings"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createGeoSettings","tags":["AI visibility settings"],"summary":"Create a ai visibility setting","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `geo-settings:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeoSettingsCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/GeoSettings"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/geo-settings/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getGeoSettings","tags":["AI visibility settings"],"summary":"Retrieve a ai visibility setting","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `geo-settings:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/GeoSettings"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateGeoSettings","tags":["AI visibility settings"],"summary":"Update a ai visibility setting","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `geo-settings:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeoSettingsUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/GeoSettings"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/geo-settings/actions":{"get":{"operationId":"listGeoSettingsActions","tags":["AI visibility settings"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `geo-settings:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/geo-prompts":{"get":{"operationId":"listGeoPrompts","tags":["AI visibility prompts"],"summary":"List ai visibility prompts","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `geo-prompts:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["position","-position","createdAt","-createdAt","text","-text"],"default":"position"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: text, topic.","schema":{"type":"string"}},{"name":"filter[active]","in":"query","description":"Exact match on `active`.","schema":{"type":"string","enum":["true","false"]}},{"name":"filter[topic]","in":"query","description":"Exact match on `topic`.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GeoPrompts"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createGeoPrompts","tags":["AI visibility prompts"],"summary":"Create a ai visibility prompt","description":"Links are given as the target's **public** id (`clientId: \"hsbftmp3f5\"`); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.\n\n**Required scope:** `geo-prompts:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeoPromptsCreate"}}}},"responses":{"201":{"description":"Created. The body is the new record, as a read would return it.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/GeoPrompts"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/geo-prompts/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getGeoPrompts","tags":["AI visibility prompts"],"summary":"Retrieve a ai visibility prompt","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `geo-prompts:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/GeoPrompts"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"patch":{"operationId":"updateGeoPrompts","tags":["AI visibility prompts"],"summary":"Update a ai visibility prompt","description":"A partial update: only the fields you send change. **One exception** — `customFields` is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.\n\n**Required scope:** `geo-prompts:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeoPromptsUpdate"}}}},"responses":{"200":{"description":"Updated. The body is the record as it now stands.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/GeoPrompts"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteGeoPrompts","tags":["AI visibility prompts"],"summary":"Delete a ai visibility prompt","description":"Permanent. The audit log keeps the trace; the record does not come back.\n\n**Required scope:** `geo-prompts:write`.","responses":{"204":{"description":"Deleted. Empty body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/geo-prompts/actions":{"get":{"operationId":"listGeoPromptsActions","tags":["AI visibility prompts"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `geo-prompts:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/review-remarks":{"get":{"operationId":"listReviewRemarks","tags":["Review remarks"],"summary":"List review remarks","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `review-remarks:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt","status","-status","kind","-kind"],"default":"-createdAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: body, elementText, pagePath, pageTitle.","schema":{"type":"string"}},{"name":"filter[status]","in":"query","description":"Exact match on `status`.","schema":{"type":"string"}},{"name":"filter[kind]","in":"query","description":"Exact match on `kind`.","schema":{"type":"string"}},{"name":"filter[clientId]","in":"query","description":"Exact match on `clientId`.","schema":{"type":"string"}},{"name":"filter[projectId]","in":"query","description":"Exact match on `projectId`.","schema":{"type":"string"}},{"name":"filter[pagePath]","in":"query","description":"Exact match on `pagePath`.","schema":{"type":"string"}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ReviewRemarks"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/review-remarks/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getReviewRemarks","tags":["Review remarks"],"summary":"Retrieve a review remark","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `review-remarks:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ReviewRemarks"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/review-remarks/actions":{"get":{"operationId":"listReviewRemarksActions","tags":["Review remarks"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `review-remarks:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/review-remarks/{id}/actions/propose-fix":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runReviewRemarksProposeFix","tags":["Review remarks"],"summary":"Propose a fix for this remark","description":"Records the change proposed for this remark — a pull request, usually — and posts the link in the linked work item's feed when it has one. It changes no status: proposing a fix is not fixing it.\n\nDoes what the dashboard's `proposeWidgetFixAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `review-remarks:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","minLength":1,"maxLength":2000}},"required":["url"],"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/review-remarks/{id}/actions/dismiss":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runReviewRemarksDismiss","tags":["Review remarks"],"summary":"Dismiss this remark","description":"Sets the remark aside without making work of it — a test, a duplicate, a remark that answered itself. The row is kept: the page it came from is the only record of what the reviewer was looking at. A remark already filed as a ticket cannot be dismissed; archive the ticket instead.\n\nDoes what the dashboard's `dismissWidgetFeedbackAction` does — same implementation, so the two cannot diverge. Takes no body.\n\n**Required scope:** `review-remarks:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/review-remarks/{id}/actions/resolve":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The **public** id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it."}],"post":{"operationId":"runReviewRemarksResolve","tags":["Review remarks"],"summary":"Mark this remark resolved","description":"Closes an in-progress review remark after the delivered change was verified.\n\nDoes what the dashboard's `resolveWidgetFeedbackAction` does — same implementation, so the two cannot diverge.\n\n**Required scope:** `review-remarks:write`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A value you choose (a UUID is the usual one), 8 to 255 characters of `A-Z a-z 0-9 _ . : -`. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.","schema":{"type":"string","minLength":8,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":false}}}},"responses":{"200":{"description":"Done.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"description":"The action's result; its shape depends on the verb."}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/review-sites":{"get":{"operationId":"listReviewSites","tags":["Review sites"],"summary":"List review sites","description":"One page of records, newest first unless you say otherwise, with the total count in `meta` so you know how far to paginate.\n\n**Required scope:** `review-sites:read`.","parameters":[{"name":"page","in":"query","description":"1-based. `meta.totalPages` says how many there are.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"per_page","in":"query","description":"Rows per page. A value above 200 returns 400 — never a silent clamp.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"sort","in":"query","description":"Prefix with `-` for descending. An undeclared sort returns 400.","schema":{"type":"string","enum":["createdAt","-createdAt","name","-name"],"default":"-createdAt"}},{"name":"q","in":"query","description":"Case-insensitive \"contains\", across: name, repository.","schema":{"type":"string"}},{"name":"filter[clientId]","in":"query","description":"Exact match on `clientId`.","schema":{"type":"string"}},{"name":"filter[projectId]","in":"query","description":"Exact match on `projectId`.","schema":{"type":"string"}},{"name":"filter[enabled]","in":"query","description":"Exact match on `enabled`.","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"The requested page.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ReviewSites"}},"meta":{"$ref":"#/components/schemas/ListMeta"}},"required":["data","meta"]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/review-sites/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The record's **public** id (`hsbftmp3f5`), as returned in the `id` field. An internal UUID returns 404."}],"get":{"operationId":"getReviewSites","tags":["Review sites"],"summary":"Retrieve a review site","description":"The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 — its existence is not ours to confirm.\n\n**Required scope:** `review-sites:read`.","responses":{"200":{"description":"Found.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ReviewSites"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/review-sites/actions":{"get":{"operationId":"listReviewSitesActions","tags":["Review sites"],"summary":"List available actions","description":"Every verb this resource answers to, with its target and the JSON Schema of its body — the same contracts this document describes, readable at runtime.\n\n**Required scope:** `review-sites:read`.","responses":{"200":{"description":"The available verbs.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Cost":{"$ref":"#/components/headers/X-Quota-Cost"},"X-Quota-Used":{"$ref":"#/components/headers/X-Quota-Used"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"target":{"type":"string","enum":["item","collection"]},"path":{"type":"string"},"input":{"type":["object","null"]}},"required":["name","label","description","target","path","input"]}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/ServerError"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Your agency's API key: `Authorization: Bearer ak_…`. Created in **Settings → Integrations** and shown once. A key authenticates an agency, not a person."}},"headers":{"X-RateLimit-Limit":{"description":"Requests allowed per minute, per key.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Seconds until the window reopens.","schema":{"type":"integer"}},"X-Quota-Cost":{"description":"Tokens this call was charged.","schema":{"type":"integer"}},"X-Quota-Used":{"description":"Tokens spent since the start of the cycle.","schema":{"type":"integer"}},"X-Quota-Limit":{"description":"Monthly token allowance, or `unlimited`.","schema":{"type":"string"}},"X-Quota-Remaining":{"description":"Tokens left, or `unlimited`.","schema":{"type":"string"}},"X-Quota-Reset":{"description":"When the monthly pool resets (`YYYY-MM-DD`).","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"schemas":{"Error":{"type":"object","description":"The error envelope. Branch on `error.code`, never on the message.","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["unauthorized","forbidden","not_found","invalid_request","validation_failed","method_not_allowed","conflict","rate_limited","server_error"]},"message":{"type":"string","description":"Human-readable, written in French, and free to change."},"details":{"description":"Context you can act on: the fields that were refused, the sorts that are accepted, the reason behind a 429."},"request_id":{"type":"string","description":"This call's id, also returned as `X-Request-Id`. Quote it in a support message and the exact event is found rather than a timestamp range. Send your own `X-Request-Id` and it is echoed back instead."}},"required":["code","message","request_id"]}},"required":["error"]},"ListMeta":{"type":"object","properties":{"page":{"type":"integer"},"perPage":{"type":"integer"},"total":{"type":"integer"},"totalPages":{"type":"integer"}},"required":["page","perPage","total","totalPages"]},"Clients":{"title":"Clients","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":["string","null"]},"sector":{"type":["string","null"]},"website":{"type":["string","null"]},"linkedinUrl":{"type":["string","null"]},"siren":{"type":["string","null"]},"status":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"customFields":{"type":["object","null"],"additionalProperties":true,"description":"Your agency's custom fields, keyed by `key`. Call `GET /fields?entity=account` for the keys, their types and their choices."}},"required":["id","name","slug","sector","website","linkedinUrl","siren","status","createdAt","customFields"]},"ClientsCreate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"slug":{"anyOf":[{"type":"string","minLength":1,"maxLength":120},{"type":"null"}]},"sector":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}]},"website":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}]},"linkedinUrl":{"anyOf":[{"type":"string","maxLength":300},{"type":"null"}]},"siren":{"anyOf":[{"type":"string","maxLength":20},{"type":"null"}]},"status":{"type":"string","enum":["prospect","active","inactive","lost"]},"customFields":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["name","status"],"additionalProperties":false},"ClientsUpdate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"slug":{"anyOf":[{"type":"string","minLength":1,"maxLength":120},{"type":"null"}]},"sector":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}]},"website":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}]},"linkedinUrl":{"anyOf":[{"type":"string","maxLength":300},{"type":"null"}]},"siren":{"anyOf":[{"type":"string","maxLength":20},{"type":"null"}]},"status":{"type":"string","enum":["prospect","active","inactive","lost"]},"customFields":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"additionalProperties":false},"Contacts":{"title":"Contacts","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"role":{"type":["string","null"]},"linkedinUrl":{"type":["string","null"]},"isDecisionMaker":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"customFields":{"type":["object","null"],"additionalProperties":true,"description":"Your agency's custom fields, keyed by `key`. Call `GET /fields?entity=contact` for the keys, their types and their choices."}},"required":["id","name","firstName","lastName","email","phone","role","linkedinUrl","isDecisionMaker","createdAt","customFields"]},"ContactsCreate":{"type":"object","properties":{"firstName":{"type":"string","minLength":1,"maxLength":80},"lastName":{"type":"string","maxLength":80},"email":{"anyOf":[{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}]},"role":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}]},"linkedinUrl":{"anyOf":[{"type":"string","maxLength":300},{"type":"null"}]},"isDecisionMaker":{"type":"boolean"},"clientId":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["firstName"],"additionalProperties":false},"ContactsUpdate":{"type":"object","properties":{"firstName":{"type":"string","minLength":1,"maxLength":80},"lastName":{"type":"string","maxLength":80},"email":{"anyOf":[{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}]},"role":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}]},"linkedinUrl":{"anyOf":[{"type":"string","maxLength":300},{"type":"null"}]},"isDecisionMaker":{"type":"boolean"},"clientId":{"anyOf":[{"type":"string"},{"type":"null"}]}},"additionalProperties":false},"Deals":{"title":"Deals","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"valueCents":{"type":["integer","null"]},"status":{"type":"string","enum":["open","won","lost"]},"notes":{"type":["string","null"]},"expectedCloseAt":{"type":["string","null"],"format":"date-time"},"wonAt":{"type":["string","null"],"format":"date-time"},"lostAt":{"type":["string","null"],"format":"date-time"},"lostReasonId":{"type":["string","null"]},"lostReasonLabel":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"customFields":{"type":["object","null"],"additionalProperties":true,"description":"Your agency's custom fields, keyed by `key`. Call `GET /fields?entity=deal` for the keys, their types and their choices."}},"required":["id","name","valueCents","status","notes","expectedCloseAt","wonAt","lostAt","lostReasonId","lostReasonLabel","createdAt","updatedAt","customFields"]},"DealsCreate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"valueCents":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"expectedCloseAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"clientId":{"anyOf":[{"type":"string"},{"type":"null"}]},"contactId":{"anyOf":[{"type":"string"},{"type":"null"}]},"stageId":{"anyOf":[{"type":"string"},{"type":"null"}]},"customFields":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["name"],"additionalProperties":false},"DealsUpdate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"valueCents":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"expectedCloseAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"clientId":{"anyOf":[{"type":"string"},{"type":"null"}]},"contactId":{"anyOf":[{"type":"string"},{"type":"null"}]},"stageId":{"anyOf":[{"type":"string"},{"type":"null"}]},"customFields":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"additionalProperties":false},"Leads":{"title":"Leads","type":"object","properties":{"id":{"type":"string"},"companyName":{"type":["string","null"]},"contactName":{"type":["string","null"]},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"website":{"type":["string","null"]},"status":{"type":"string","enum":["to_contact","contacted","following_up","qualified","converted","disqualified"]},"notes":{"type":["string","null"]},"lastContactedAt":{"type":["string","null"],"format":"date-time"},"convertedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"customFields":{"type":["object","null"],"additionalProperties":true,"description":"Your agency's custom fields, keyed by `key`. Call `GET /fields?entity=lead` for the keys, their types and their choices."}},"required":["id","companyName","contactName","email","phone","website","status","notes","lastContactedAt","convertedAt","createdAt","customFields"]},"LeadsCreate":{"type":"object","properties":{"companyName":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"contactName":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"email":{"anyOf":[{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}]},"website":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}]},"sourceId":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["to_contact","contacted","following_up","qualified","converted","disqualified"]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastContactedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"clientId":{"anyOf":[{"type":"string"},{"type":"null"}]},"customFields":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"additionalProperties":false},"LeadsUpdate":{"type":"object","properties":{"companyName":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"contactName":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"email":{"anyOf":[{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}]},"website":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}]},"sourceId":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["to_contact","contacted","following_up","qualified","converted","disqualified"]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastContactedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"clientId":{"anyOf":[{"type":"string"},{"type":"null"}]},"customFields":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"additionalProperties":false},"Projects":{"title":"Projects","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"status":{"type":"string"},"recurrencePeriod":{"type":["string","null"],"enum":["monthly","quarterly","semiannual","annual",null]},"createdAt":{"type":"string","format":"date-time"}},"required":["id","name","description","status","recurrencePeriod","createdAt"]},"ProjectsCreate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","maxLength":40},"clientId":{"anyOf":[{"type":"string"},{"type":"null"}]},"projectTypeId":{"anyOf":[{"type":"string"},{"type":"null"}]},"recurrencePeriod":{"anyOf":[{"type":"string","enum":["monthly","quarterly","semiannual","annual"]},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["name"],"additionalProperties":false},"ProjectsUpdate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","maxLength":40},"clientId":{"anyOf":[{"type":"string"},{"type":"null"}]},"projectTypeId":{"anyOf":[{"type":"string"},{"type":"null"}]},"recurrencePeriod":{"anyOf":[{"type":"string","enum":["monthly","quarterly","semiannual","annual"]},{"type":"null"}]}},"additionalProperties":false},"Tickets":{"title":"Tickets","type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"scope":{"type":"string","enum":["client","agency","internal"]},"status":{"type":"string"},"priority":{"type":"string","enum":["low","medium","high","urgent"]},"clientVisible":{"type":"boolean"},"dueDate":{"type":["string","null"],"format":"date-time"},"estimateMinutes":{"type":["integer","null"]},"commitRef":{"type":["string","null"]},"resolvedAt":{"type":["string","null"],"format":"date-time"},"resolvedById":{"type":["string","null"]},"archivedAt":{"type":["string","null"],"format":"date-time"},"clientId":{"type":["string","null"]},"projectId":{"type":["string","null"]},"parentId":{"type":["string","null"]},"assigneeId":{"type":["string","null"]},"categoryId":{"type":["string","null"]},"teamId":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"customFields":{"type":["object","null"],"additionalProperties":true,"description":"Your agency's custom fields, keyed by `key`. Call `GET /fields?entity=ticket` for the keys, their types and their choices."}},"required":["id","title","description","scope","status","priority","clientVisible","dueDate","estimateMinutes","commitRef","resolvedAt","resolvedById","archivedAt","clientId","projectId","parentId","assigneeId","categoryId","teamId","createdAt","customFields"]},"TicketsCreate":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":300},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"scope":{"type":"string","enum":["client","agency","internal"]},"status":{"type":"string","minLength":1,"maxLength":40},"priority":{"type":"string","enum":["low","medium","high","urgent"]},"clientVisible":{"type":"boolean"},"dueDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"estimateMinutes":{"anyOf":[{"type":"integer","minimum":0,"maximum":9007199254740991},{"type":"null"}]},"commitRef":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}]},"clientId":{"anyOf":[{"type":"string"},{"type":"null"}]},"projectId":{"anyOf":[{"type":"string"},{"type":"null"}]},"parentId":{"anyOf":[{"type":"string"},{"type":"null"}]},"assigneeId":{"anyOf":[{"type":"string"},{"type":"null"}]},"categoryId":{"anyOf":[{"type":"string"},{"type":"null"}]},"customFields":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["title"],"additionalProperties":false},"TicketsUpdate":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":300},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"scope":{"type":"string","enum":["client","agency","internal"]},"status":{"type":"string","minLength":1,"maxLength":40},"priority":{"type":"string","enum":["low","medium","high","urgent"]},"clientVisible":{"type":"boolean"},"dueDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"estimateMinutes":{"anyOf":[{"type":"integer","minimum":0,"maximum":9007199254740991},{"type":"null"}]},"commitRef":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}]},"clientId":{"anyOf":[{"type":"string"},{"type":"null"}]},"projectId":{"anyOf":[{"type":"string"},{"type":"null"}]},"parentId":{"anyOf":[{"type":"string"},{"type":"null"}]},"assigneeId":{"anyOf":[{"type":"string"},{"type":"null"}]},"categoryId":{"anyOf":[{"type":"string"},{"type":"null"}]},"customFields":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"additionalProperties":false},"TimeLogs":{"title":"Time logs","type":"object","properties":{"id":{"type":"string"},"durationMinutes":{"type":"integer"},"note":{"type":["string","null"]},"billable":{"type":"boolean"},"startedAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","durationMinutes","note","billable","startedAt","createdAt"]},"TimeLogsCreate":{"type":"object","properties":{"durationMinutes":{"type":"integer","minimum":1,"maximum":9007199254740991},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"billable":{"type":"boolean"},"startedAt":{"type":"string"},"ticketId":{"anyOf":[{"type":"string"},{"type":"null"}]},"clientId":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["durationMinutes"],"additionalProperties":false},"TimeLogsUpdate":{"type":"object","properties":{"durationMinutes":{"type":"integer","minimum":1,"maximum":9007199254740991},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"billable":{"type":"boolean"},"startedAt":{"type":"string"},"ticketId":{"anyOf":[{"type":"string"},{"type":"null"}]},"clientId":{"anyOf":[{"type":"string"},{"type":"null"}]}},"additionalProperties":false},"WorkflowStatuses":{"title":"Workflow columns","type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"color":{"type":"string"},"position":{"type":"integer"},"isDone":{"type":"boolean"}},"required":["id","label","color","position","isDone"]},"Forfaits":{"title":"Retainers","type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["monthly","project","quarterly","semiannual","annual"]},"amountMinutes":{"type":"integer"},"rollsOver":{"type":"boolean"},"periodStart":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","type","amountMinutes","rollsOver","periodStart","createdAt"]},"ForfaitsCreate":{"type":"object","properties":{"amountMinutes":{"type":"integer","minimum":0,"maximum":9007199254740991},"type":{"type":"string","enum":["monthly","project"]},"rollsOver":{"type":"boolean"},"periodStart":{"anyOf":[{"type":"string"},{"type":"null"}]},"clientId":{"type":"string"},"projectId":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["amountMinutes","clientId"],"additionalProperties":false},"ForfaitsUpdate":{"type":"object","properties":{"amountMinutes":{"type":"integer","minimum":0,"maximum":9007199254740991},"type":{"type":"string","enum":["monthly","project"]},"rollsOver":{"type":"boolean"},"periodStart":{"anyOf":[{"type":"string"},{"type":"null"}]},"clientId":{"type":"string"},"projectId":{"anyOf":[{"type":"string"},{"type":"null"}]}},"additionalProperties":false},"Docs":{"title":"Docs","type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"body":{"type":["string","null"]},"blocks":{},"content":{},"icon":{"type":["string","null"]},"clientVisible":{"type":"boolean"},"portalScope":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","title","body","blocks","content","icon","clientVisible","portalScope","createdAt","updatedAt"]},"DocsCreate":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":300},"body":{"anyOf":[{"type":"string","maxLength":200000},{"type":"null"}]},"blocks":{"type":"array","items":{}},"content":{"anyOf":[{"type":"array","items":{}},{"type":"null"}]},"icon":{"anyOf":[{"type":"string","maxLength":20},{"type":"null"}]},"clientVisible":{"type":"boolean"},"portalScope":{"type":"string","enum":["internal","account","clients","all"]},"clientId":{"anyOf":[{"type":"string"},{"type":"null"}]},"projectId":{"anyOf":[{"type":"string"},{"type":"null"}]},"parentId":{"anyOf":[{"type":"string"},{"type":"null"}]},"folderId":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["title"],"additionalProperties":false},"DocsUpdate":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":300},"body":{"anyOf":[{"type":"string","maxLength":200000},{"type":"null"}]},"blocks":{"type":"array","items":{}},"content":{"anyOf":[{"type":"array","items":{}},{"type":"null"}]},"icon":{"anyOf":[{"type":"string","maxLength":20},{"type":"null"}]},"clientVisible":{"type":"boolean"},"portalScope":{"type":"string","enum":["internal","account","clients","all"]},"clientId":{"anyOf":[{"type":"string"},{"type":"null"}]},"projectId":{"anyOf":[{"type":"string"},{"type":"null"}]},"parentId":{"anyOf":[{"type":"string"},{"type":"null"}]},"folderId":{"anyOf":[{"type":"string"},{"type":"null"}]}},"additionalProperties":false},"Categories":{"title":"Categories","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"color":{"type":["string","null"]},"billableDefault":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","name","color","billableDefault","createdAt"]},"Teams":{"title":"Teams","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"position":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","name","position","createdAt"]},"Pipelines":{"title":"Pipelines","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"position":{"type":"integer"},"isDefault":{"type":"boolean"},"onWinActivateAccount":{"type":"boolean"},"onWinProject":{"type":"string","enum":["create","create_or_attach","none"]},"archivedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","name","position","isDefault","onWinActivateAccount","onWinProject","archivedAt","createdAt"]},"PipelinesCreate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80},"onWinActivateAccount":{"type":"boolean"},"onWinProject":{"type":"string","enum":["create","create_or_attach","none"]},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["name"],"additionalProperties":false},"PipelinesUpdate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80},"onWinActivateAccount":{"type":"boolean"},"onWinProject":{"type":"string","enum":["create","create_or_attach","none"]},"archivedAt":{"anyOf":[{},{"type":"null"}]}},"additionalProperties":false},"PipelineStages":{"title":"Pipeline stages","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["open","won","lost"]},"position":{"type":"integer"},"pipelineId":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"}},"required":["id","name","kind","position","pipelineId","createdAt"]},"Members":{"title":"Members","type":"object","properties":{"id":{"type":"string"},"name":{"type":["string","null"]},"email":{"type":["string","null"]},"role":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","name","email","role","createdAt"]},"FieldDefinitions":{"title":"Custom fields","type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"},"label":{"type":"string"},"type":{"type":"string","enum":["text","long_text","number","date","select","multi_select","checkbox","url","user","email"]},"entity":{"type":"string","enum":["ticket","deal","account","lead","contact"]},"options":{},"required":{"type":"boolean"},"clientVisible":{"type":"boolean"},"scope":{"type":["string","null"],"enum":["client","agency","internal",null]},"showInCreate":{"type":"boolean"},"showInDetail":{"type":"boolean"},"category":{"type":["string","null"]},"position":{"type":"integer"},"archived":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","key","label","type","entity","options","required","clientVisible","scope","showInCreate","showInDetail","category","position","archived","createdAt"]},"FieldDefinitionsCreate":{"type":"object","properties":{"key":{"type":"string","minLength":1,"maxLength":60,"pattern":"^[a-z][a-z0-9_]*$"},"label":{"type":"string","minLength":1,"maxLength":120},"type":{"type":"string","enum":["text","long_text","number","date","select","multi_select","checkbox","url","email","user"]},"entity":{"type":"string","enum":["ticket","deal","account","lead","contact"]},"options":{"maxItems":100,"type":"array","items":{"anyOf":[{"type":"string","minLength":1,"maxLength":120},{"type":"object","properties":{"value":{"type":"string","minLength":1,"maxLength":120},"label":{"type":"string","minLength":1,"maxLength":120},"color":{"type":"string","maxLength":30}},"required":["value","label"]}]}},"required":{"type":"boolean"},"clientVisible":{"type":"boolean"},"scope":{"anyOf":[{"type":"string","enum":["client","agency","internal"]},{"type":"null"}]},"showInCreate":{"type":"boolean"},"showInDetail":{"type":"boolean"},"category":{"anyOf":[{"type":"string","maxLength":80},{"type":"null"}]},"position":{"type":"integer","minimum":0,"maximum":9999},"archived":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["key","label","type","entity"],"additionalProperties":false},"FieldDefinitionsUpdate":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":120},"options":{"maxItems":100,"type":"array","items":{"anyOf":[{"type":"string","minLength":1,"maxLength":120},{"type":"object","properties":{"value":{"type":"string","minLength":1,"maxLength":120},"label":{"type":"string","minLength":1,"maxLength":120},"color":{"type":"string","maxLength":30}},"required":["value","label"]}]}},"required":{"type":"boolean"},"clientVisible":{"type":"boolean"},"scope":{"anyOf":[{"type":"string","enum":["client","agency","internal"]},{"type":"null"}]},"showInCreate":{"type":"boolean"},"showInDetail":{"type":"boolean"},"category":{"anyOf":[{"type":"string","maxLength":80},{"type":"null"}]},"position":{"type":"integer","minimum":0,"maximum":9999},"archived":{"type":"boolean"}},"additionalProperties":false},"Comments":{"title":"Comments","type":"object","properties":{"id":{"type":"string"},"body":{"type":"string"},"clientVisible":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","body","clientVisible","createdAt"]},"CommentsCreate":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":10000},"clientVisible":{"type":"boolean"},"ticketId":{"type":"string"},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["body","ticketId"],"additionalProperties":false},"CommentsUpdate":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":10000},"clientVisible":{"type":"boolean"},"ticketId":{"type":"string"}},"additionalProperties":false},"Activities":{"title":"Activities","type":"object","properties":{"id":{"type":"string"},"type":{"type":"string"},"title":{"type":"string"},"note":{"type":["string","null"]},"startAt":{"type":"string","format":"date-time"},"endAt":{"type":["string","null"],"format":"date-time"},"priority":{"type":"string"},"clientVisible":{"type":"boolean"},"done":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","type","title","note","startAt","endAt","priority","clientVisible","done","createdAt"]},"ActivitiesCreate":{"type":"object","properties":{"type":{"type":"string","enum":["call","meeting","task","deadline","email","lunch","other"]},"title":{"type":"string","minLength":1,"maxLength":200},"note":{"anyOf":[{"type":"string","maxLength":10000},{"type":"null"}]},"startAt":{"type":"string"},"endAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"priority":{"type":"string","enum":["low","medium","high","urgent"]},"clientVisible":{"type":"boolean"},"done":{"type":"boolean"},"clientId":{"type":"string"},"dealId":{"anyOf":[{"type":"string"},{"type":"null"}]},"projectId":{"anyOf":[{"type":"string"},{"type":"null"}]},"contactId":{"anyOf":[{"type":"string"},{"type":"null"}]},"assigneeId":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["type","title","startAt","clientId"],"additionalProperties":false},"ActivitiesUpdate":{"type":"object","properties":{"type":{"type":"string","enum":["call","meeting","task","deadline","email","lunch","other"]},"title":{"type":"string","minLength":1,"maxLength":200},"note":{"anyOf":[{"type":"string","maxLength":10000},{"type":"null"}]},"startAt":{"type":"string"},"endAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"priority":{"type":"string","enum":["low","medium","high","urgent"]},"clientVisible":{"type":"boolean"},"done":{"type":"boolean"},"clientId":{"type":"string"},"dealId":{"anyOf":[{"type":"string"},{"type":"null"}]},"projectId":{"anyOf":[{"type":"string"},{"type":"null"}]},"contactId":{"anyOf":[{"type":"string"},{"type":"null"}]},"assigneeId":{"anyOf":[{"type":"string"},{"type":"null"}]}},"additionalProperties":false},"Proposals":{"title":"Proposals","type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"status":{"type":"string","enum":["draft","sent","viewed","accepted","declined","paid"]},"document":{},"locale":{"type":"string"},"clientName":{"type":["string","null"]},"currency":{"type":"string"},"amountCents":{"type":["integer","null"]},"forfaitType":{"type":["string","null"],"enum":["monthly","project","quarterly","semiannual","annual",null]},"forfaitMinutes":{"type":["integer","null"]},"viewCount":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","title","status","document","locale","clientName","currency","amountCents","forfaitType","forfaitMinutes","viewCount","createdAt","updatedAt"]},"ProposalsCreate":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":200},"document":{"type":"array","items":{}},"locale":{"type":"string","enum":["fr","en"]},"clientName":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"currency":{"type":"string","minLength":3,"maxLength":3},"amountCents":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"forfaitType":{"anyOf":[{"type":"string","enum":["monthly","project"]},{"type":"null"}]},"forfaitMinutes":{"anyOf":[{"type":"integer","minimum":0,"maximum":9007199254740991},{"type":"null"}]},"dealId":{"anyOf":[{"type":"string"},{"type":"null"}]},"projectId":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["title"],"additionalProperties":false},"ProposalsUpdate":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":200},"document":{"type":"array","items":{}},"locale":{"type":"string","enum":["fr","en"]},"clientName":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"currency":{"type":"string","minLength":3,"maxLength":3},"amountCents":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"forfaitType":{"anyOf":[{"type":"string","enum":["monthly","project"]},{"type":"null"}]},"forfaitMinutes":{"anyOf":[{"type":"integer","minimum":0,"maximum":9007199254740991},{"type":"null"}]},"dealId":{"anyOf":[{"type":"string"},{"type":"null"}]},"projectId":{"anyOf":[{"type":"string"},{"type":"null"}]}},"additionalProperties":false},"Reports":{"title":"Reports","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"layout":{},"periodConfig":{},"portalVisible":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","name","layout","periodConfig","portalVisible","createdAt","updatedAt"]},"ReportsCreate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"layout":{"type":"array","items":{}},"periodConfig":{"type":"object","properties":{"historyPoints":{"type":"integer","minimum":1,"maximum":60}},"required":["historyPoints"]},"portalVisible":{"type":"boolean"},"clientId":{"type":"string"},"projectId":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["name","clientId"],"additionalProperties":false},"ReportsUpdate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"layout":{"type":"array","items":{}},"periodConfig":{"type":"object","properties":{"historyPoints":{"type":"integer","minimum":1,"maximum":60}},"required":["historyPoints"]},"portalVisible":{"type":"boolean"},"clientId":{"type":"string"},"projectId":{"anyOf":[{"type":"string"},{"type":"null"}]}},"additionalProperties":false},"ReportTemplates":{"title":"Report templates","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"layout":{},"periodConfig":{},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","name","layout","periodConfig","createdAt","updatedAt"]},"ReportSchedules":{"title":"Report schedules","type":"object","properties":{"id":{"type":"string"},"portalVisible":{"type":"boolean"},"active":{"type":"boolean"},"lastRunAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","portalVisible","active","lastRunAt","createdAt","updatedAt"]},"ChatChannels":{"title":"Chat channels","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"audience":{"type":"string","enum":["all","internal","partners"]},"position":{"type":"integer"},"projectId":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"}},"required":["id","name","audience","position","projectId","createdAt"]},"ChatChannelsCreate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"audience":{"type":"string","enum":["all","internal","client"]},"position":{"type":"integer","minimum":0,"maximum":9999},"projectId":{"type":"string"},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["name","projectId"],"additionalProperties":false},"ChatChannelsUpdate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"audience":{"type":"string","enum":["all","internal","client"]},"position":{"type":"integer","minimum":0,"maximum":9999},"projectId":{"type":"string"}},"additionalProperties":false},"ChatMessages":{"title":"Chat messages","type":"object","properties":{"id":{"type":"string"},"body":{"type":"string"},"channelId":{"type":["string","null"]},"projectId":{"type":["string","null"]},"parentId":{"type":["string","null"]},"authorId":{"type":["string","null"]},"replyCount":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","body","channelId","projectId","parentId","authorId","replyCount","createdAt"]},"ChatMessagesCreate":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":10000},"channelId":{"type":"string"},"parentId":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["body","channelId"],"additionalProperties":false},"ChatMessagesUpdate":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":10000},"channelId":{"type":"string"},"parentId":{"anyOf":[{"type":"string"},{"type":"null"}]}},"additionalProperties":false},"Decks":{"title":"Decks","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"layout":{},"periodConfig":{},"dataMode":{"type":"string"},"portalVisible":{"type":"boolean"},"viewCount":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","name","layout","periodConfig","dataMode","portalVisible","viewCount","createdAt","updatedAt"]},"DecksCreate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"layout":{"type":"array","items":{}},"periodConfig":{"type":"object","properties":{"historyPoints":{"type":"integer","minimum":1,"maximum":60}},"required":["historyPoints"]},"dataMode":{"type":"string","enum":["live","frozen"]},"portalVisible":{"type":"boolean"},"clientId":{"type":"string"},"projectId":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["name","clientId"],"additionalProperties":false},"DecksUpdate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"layout":{"type":"array","items":{}},"periodConfig":{"type":"object","properties":{"historyPoints":{"type":"integer","minimum":1,"maximum":60}},"required":["historyPoints"]},"dataMode":{"type":"string","enum":["live","frozen"]},"portalVisible":{"type":"boolean"},"clientId":{"type":"string"},"projectId":{"anyOf":[{"type":"string"},{"type":"null"}]}},"additionalProperties":false},"DeckComments":{"title":"Deck comments","type":"object","properties":{"id":{"type":"string"},"slideIndex":{"type":"integer"},"authorName":{"type":"string"},"body":{"type":"string"},"resolvedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","slideIndex","authorName","body","resolvedAt","createdAt"]},"PortalInvitations":{"title":"Portal invitations","type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"roleKey":{"type":"string"},"status":{"type":"string"},"expiresAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","email","roleKey","status","expiresAt","createdAt"]},"PortalInvitationsCreate":{"type":"object","properties":{"email":{"type":"string","maxLength":200,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"roleKey":{"type":"string","enum":["client_admin","client_member"]},"clientId":{"type":"string"},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["email","clientId"],"additionalProperties":false},"PortalInvitationsUpdate":{"type":"object","properties":{"email":{"type":"string","maxLength":200,"format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"roleKey":{"type":"string","enum":["client_admin","client_member"]},"clientId":{"type":"string"},"status":{"type":"string","enum":["revoked"]}},"additionalProperties":false},"ConnectorConnections":{"title":"Connectors","type":"object","properties":{"id":{"type":"string"},"connectorId":{"type":"string"},"enabled":{"type":"boolean"},"portalVisible":{"type":"boolean"},"frequency":{"type":"string"},"config":{},"status":{"type":"string"},"lastError":{"type":["string","null"]},"lastSyncedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","connectorId","enabled","portalVisible","frequency","config","status","lastError","lastSyncedAt","createdAt","updatedAt"]},"ConnectorConnectionsCreate":{"type":"object","properties":{"connectorId":{"type":"string","minLength":1,"maxLength":60},"enabled":{"type":"boolean"},"portalVisible":{"type":"boolean"},"frequency":{"type":"string","enum":["daily","weekly","monthly"]},"config":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"clientId":{"type":"string"},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["connectorId","clientId"],"additionalProperties":false},"ConnectorConnectionsUpdate":{"type":"object","properties":{"connectorId":{"type":"string","minLength":1,"maxLength":60},"enabled":{"type":"boolean"},"portalVisible":{"type":"boolean"},"frequency":{"type":"string","enum":["daily","weekly","monthly"]},"config":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"clientId":{"type":"string"}},"additionalProperties":false},"AgencySettings":{"title":"Agency settings","type":"object","properties":{"id":{"type":"string"},"timezone":{"type":"string"},"portalShowForfaitHours":{"type":"boolean"},"reviewLinks":{},"clientCreateFields":{},"recordDeletionEnabled":{"type":"boolean"},"npsTemplate":{},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","timezone","portalShowForfaitHours","reviewLinks","clientCreateFields","recordDeletionEnabled","npsTemplate","updatedAt"]},"Branding":{"title":"Portal branding","type":"object","properties":{"id":{"type":"string"},"logoUrl":{"type":["string","null"]},"accentColor":{"type":["string","null"]},"welcomeMessage":{"type":["string","null"]},"welcomeVideoUrl":{"type":["string","null"]},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","logoUrl","accentColor","welcomeMessage","welcomeVideoUrl","updatedAt"]},"DocFolders":{"title":"Doc folders","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","name","createdAt","updatedAt"]},"DocFoldersCreate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"parentId":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["name"],"additionalProperties":false},"DocFoldersUpdate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"parentId":{"anyOf":[{"type":"string"},{"type":"null"}]}},"additionalProperties":false},"LostReasons":{"title":"Lost reasons","type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"position":{"type":"integer"},"archived":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","label","position","archived","createdAt"]},"LostReasonsCreate":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":80},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["label"],"additionalProperties":false},"LostReasonsUpdate":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":80},"archived":{"type":"boolean"}},"additionalProperties":false},"LeadSources":{"title":"Lead sources","type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"position":{"type":"integer"},"archived":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","label","position","archived","createdAt"]},"LeadSourcesCreate":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":80},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["label"],"additionalProperties":false},"LeadSourcesUpdate":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":80},"archived":{"type":"boolean"}},"additionalProperties":false},"ContactRoles":{"title":"Contact roles","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"position":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","name","position","createdAt"]},"ContactRolesCreate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":60},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["name"],"additionalProperties":false},"ContactRolesUpdate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":60}},"additionalProperties":false},"TaxRates":{"title":"Tax rates","type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"rateBps":{"type":"integer"},"country":{"type":["string","null"]},"isDefault":{"type":"boolean"},"position":{"type":"integer"},"archived":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","label","rateBps","country","isDefault","position","archived","createdAt"]},"TaxRatesCreate":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":80},"rateBps":{"type":"integer","minimum":0,"maximum":10000},"country":{"type":"string","pattern":"^[A-Z]{2}$"},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["label","rateBps"],"additionalProperties":false},"TaxRatesUpdate":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":80},"rateBps":{"type":"integer","minimum":0,"maximum":10000},"country":{"anyOf":[{"type":"string","pattern":"^[A-Z]{2}$"},{"type":"null"}]},"archived":{"type":"boolean"}},"additionalProperties":false},"DealProducts":{"title":"Deal products","type":"object","properties":{"id":{"type":"string"},"dealId":{"type":["string","null"]},"name":{"type":"string"},"quantity":{"type":"string","description":"Exact decimal, carried as a string."},"unitAmountCents":{"type":"integer"},"position":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","dealId","name","quantity","unitAmountCents","position","createdAt"]},"Products":{"title":"Products","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"descriptionHtml":{"type":"string"},"unitAmountCents":{"type":"integer"},"currency":{"type":"string"},"reference":{"type":["string","null"]},"designation":{"type":["string","null"]},"nature":{"type":"string","enum":["service","goods"]},"unit":{"type":"string","enum":["none","hour","day","month","percent","kg","m","m2","m3","ton","mg","flat_rate"]},"defaultQuantity":{"type":"string","description":"Exact decimal, carried as a string."},"pricingMode":{"type":"string","enum":["fixed","on_quote"]},"taxRateBps":{"type":"integer"},"taxRatePct":{"type":"string","description":"Exact decimal, carried as a string."},"kind":{"type":"string","enum":["one_shot","recurring"]},"active":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","name","description","descriptionHtml","unitAmountCents","currency","reference","designation","nature","unit","defaultQuantity","pricingMode","taxRateBps","taxRatePct","kind","active","createdAt"]},"ProductsCreate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"description":{"type":"string","maxLength":2000},"unitAmountCents":{"type":"integer","minimum":0,"maximum":999999900},"currency":{"type":"string","minLength":3,"maxLength":3},"reference":{"type":"string","maxLength":60},"designation":{"type":"string","maxLength":200},"descriptionHtml":{"type":"string","maxLength":20000},"nature":{"type":"string","enum":["service","goods"]},"unit":{"type":"string","enum":["none","hour","day","month","percent","kg","m","m2","m3","ton","mg","flat_rate"]},"defaultQuantity":{"type":"number","minimum":0,"maximum":100000},"pricingMode":{"type":"string","enum":["fixed","on_quote"]},"taxRateBps":{"type":"integer","minimum":0,"maximum":10000},"taxRatePct":{"type":"number","minimum":0,"maximum":100},"kind":{"type":"string","enum":["one_shot","recurring"]},"active":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["name"],"additionalProperties":false},"ProductsUpdate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"description":{"type":"string","maxLength":2000},"unitAmountCents":{"type":"integer","minimum":0,"maximum":999999900},"currency":{"type":"string","minLength":3,"maxLength":3},"reference":{"type":"string","maxLength":60},"designation":{"type":"string","maxLength":200},"descriptionHtml":{"type":"string","maxLength":20000},"nature":{"type":"string","enum":["service","goods"]},"unit":{"type":"string","enum":["none","hour","day","month","percent","kg","m","m2","m3","ton","mg","flat_rate"]},"defaultQuantity":{"type":"number","minimum":0,"maximum":100000},"pricingMode":{"type":"string","enum":["fixed","on_quote"]},"taxRateBps":{"type":"integer","minimum":0,"maximum":10000},"taxRatePct":{"type":"number","minimum":0,"maximum":100},"kind":{"type":"string","enum":["one_shot","recurring"]},"active":{"type":"boolean"}},"additionalProperties":false},"ProductCategories":{"title":"Product categories","type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"position":{"type":"integer"},"archived":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","label","position","archived","createdAt"]},"ProductCategoriesCreate":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":80},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["label"],"additionalProperties":false},"ProductCategoriesUpdate":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":80},"archived":{"type":"boolean"}},"additionalProperties":false},"ProductPackages":{"title":"Product packages","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","name","description","createdAt"]},"ProductPackagesCreate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"description":{"type":"string","maxLength":2000},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["name"],"additionalProperties":false},"ProductPackagesUpdate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"description":{"type":"string","maxLength":2000}},"additionalProperties":false},"TicketTemplates":{"title":"Ticket templates","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"scope":{"type":"string","enum":["client","agency","internal"]},"priority":{"type":"string","enum":["low","medium","high","urgent"]},"clientVisible":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"customFields":{"type":["object","null"],"additionalProperties":true,"description":"Your agency's custom fields, keyed by `key`. Call `GET /fields?entity=ticket` for the keys, their types and their choices."}},"required":["id","name","title","description","scope","priority","clientVisible","createdAt","customFields"]},"TicketTemplatesCreate":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":120},"title":{"type":"string","minLength":2,"maxLength":160},"description":{"anyOf":[{"type":"string","maxLength":4000},{"type":"null"}]},"scope":{"type":"string","enum":["client","agency","internal"]},"priority":{"type":"string","enum":["low","medium","high","urgent"]},"clientVisible":{"type":"boolean"},"categoryId":{"anyOf":[{"type":"string"},{"type":"null"}]},"customFields":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["name","title"],"additionalProperties":false},"TicketTemplatesUpdate":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":120},"title":{"type":"string","minLength":2,"maxLength":160},"description":{"anyOf":[{"type":"string","maxLength":4000},{"type":"null"}]},"scope":{"type":"string","enum":["client","agency","internal"]},"priority":{"type":"string","enum":["low","medium","high","urgent"]},"clientVisible":{"type":"boolean"},"categoryId":{"anyOf":[{"type":"string"},{"type":"null"}]},"customFields":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"additionalProperties":false},"RecurringTickets":{"title":"Recurring tickets","type":"object","properties":{"id":{"type":"string"},"intervalCount":{"type":"integer"},"intervalUnit":{"type":"string","enum":["day","week","month"]},"nextRunAt":{"type":"string","format":"date-time"},"lastRunAt":{"type":["string","null"],"format":"date-time"},"active":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","intervalCount","intervalUnit","nextRunAt","lastRunAt","active","createdAt"]},"RecurringTicketsCreate":{"type":"object","properties":{"templateId":{"type":"string"},"clientId":{"anyOf":[{"type":"string"},{"type":"null"}]},"intervalCount":{"type":"integer","minimum":1,"maximum":365},"intervalUnit":{"type":"string","enum":["day","week","month"]},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["templateId","intervalCount","intervalUnit"],"additionalProperties":false},"RecurringTicketsUpdate":{"type":"object","properties":{"templateId":{"type":"string"},"clientId":{"anyOf":[{"type":"string"},{"type":"null"}]},"intervalCount":{"type":"integer","minimum":1,"maximum":365},"intervalUnit":{"type":"string","enum":["day","week","month"]},"active":{"type":"boolean"}},"additionalProperties":false},"ProjectTemplates":{"title":"Project templates","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"}},"required":["id","name","description","createdAt"]},"ProjectTemplatesCreate":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":120},"description":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["name"],"additionalProperties":false},"ProjectTemplatesUpdate":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":120},"description":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]}},"additionalProperties":false},"TicketAutomations":{"title":"Ticket automations","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"active":{"type":"boolean"},"trigger":{"type":"string"},"position":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","name","active","trigger","position","createdAt","updatedAt"]},"AutomationTags":{"title":"Automation tags","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"color":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","name","color","createdAt"]},"ProjectTypes":{"title":"Project types","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"position":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","name","description","position","createdAt"]},"ProjectTypesCreate":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":120},"description":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["name"],"additionalProperties":false},"ProjectTypesUpdate":{"type":"object","properties":{"description":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]}},"additionalProperties":false},"OnboardingTemplateSteps":{"title":"Onboarding template steps","type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["form","confirm","upload","acknowledge"]},"title":{"type":"string"},"description":{"type":["string","null"]},"config":{},"required":{"type":"boolean"},"position":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","kind","title","description","config","required","position","createdAt"]},"BillingDocuments":{"title":"Billing documents","type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["invoice","quote","other"]},"label":{"type":"string"},"fileName":{"type":"string"},"contentType":{"type":["string","null"]},"sizeBytes":{"type":"integer"},"amountCents":{"type":["integer","null"]},"currency":{"type":"string"},"issuedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","kind","label","fileName","contentType","sizeBytes","amountCents","currency","issuedAt","createdAt"]},"Domains":{"title":"Domains","type":"object","properties":{"id":{"type":"string"},"domain":{"type":"string"},"verified":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","domain","verified","createdAt"]},"BlogPosts":{"title":"Blog posts","type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"title":{"type":"string"},"excerpt":{"type":["string","null"]},"coverImageUrl":{"type":["string","null"]},"blocks":{},"status":{"type":"string"},"publishedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","slug","title","excerpt","coverImageUrl","blocks","status","publishedAt","createdAt","updatedAt"]},"Partners":{"title":"Partners","type":"object","properties":{"id":{"type":"string"},"clientId":{"type":["string","null"]},"clientName":{"type":["string","null"]},"contactId":{"type":["string","null"]},"contactName":{"type":["string","null"]},"kind":{"type":"string","enum":["agency","freelance","referrer","consultant"]},"tier":{"type":["string","null"]},"notes":{"type":["string","null"]},"status":{"type":"string"},"defaultCommissionBps":{"type":["integer","null"]},"defaultBillingMode":{"type":"string","enum":["we_invoice","partner_invoices"]},"defaultCompKind":{"type":"string","enum":["commission_pct","fixed_amount","none"]},"defaultCompBase":{"type":"string","enum":["deal_total","agency_share","custom"]},"defaultSharedFields":{},"createdAt":{"type":"string","format":"date-time"}},"required":["id","clientId","clientName","contactId","contactName","kind","tier","notes","status","defaultCommissionBps","defaultBillingMode","defaultCompKind","defaultCompBase","defaultSharedFields","createdAt"]},"PartnersCreate":{"type":"object","properties":{"clientId":{"anyOf":[{"type":"string"},{"type":"null"}]},"contactId":{"anyOf":[{"type":"string"},{"type":"null"}]},"kind":{"type":"string","enum":["agency","freelance","referrer","consultant"]},"tier":{"anyOf":[{"type":"string","maxLength":80},{"type":"null"}]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"defaultCommissionBps":{"anyOf":[{"type":"integer","minimum":0,"maximum":1000000},{"type":"null"}]},"defaultBillingMode":{"type":"string","enum":["we_invoice","partner_invoices"]},"defaultCompKind":{"type":"string","enum":["commission_pct","fixed_amount","none"]},"defaultCompBase":{"type":"string","enum":["deal_total","agency_share","custom"]},"defaultSharedFields":{"type":"array","items":{"type":"string","enum":["deal.name","deal.stage","deal.value","deal.agency_share","deal.expected_close","deal.notes","partner.share","partner.commission","account.name","account.contacts","documents","activity"]}},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"additionalProperties":false},"PartnersUpdate":{"type":"object","properties":{"kind":{"type":"string","enum":["agency","freelance","referrer","consultant"]},"tier":{"anyOf":[{"type":"string","maxLength":80},{"type":"null"}]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["active","revoked"]},"defaultCommissionBps":{"anyOf":[{"type":"integer","minimum":0,"maximum":1000000},{"type":"null"}]},"defaultBillingMode":{"type":"string","enum":["we_invoice","partner_invoices"]},"defaultCompKind":{"type":"string","enum":["commission_pct","fixed_amount","none"]},"defaultCompBase":{"type":"string","enum":["deal_total","agency_share","custom"]},"defaultSharedFields":{"type":"array","items":{"type":"string","enum":["deal.name","deal.stage","deal.value","deal.agency_share","deal.expected_close","deal.notes","partner.share","partner.commission","account.name","account.contacts","documents","activity"]}}},"additionalProperties":false},"DealPartners":{"title":"Deal partners","type":"object","properties":{"id":{"type":"string"},"dealId":{"type":["string","null"]},"dealName":{"type":["string","null"]},"partnerId":{"type":["string","null"]},"role":{"type":"string","enum":["referrer","subcontractor","reseller"]},"billingMode":{"type":"string","enum":["we_invoice","partner_invoices"]},"compKind":{"type":"string","enum":["commission_pct","fixed_amount","none"]},"compBase":{"type":"string","enum":["deal_total","agency_share","custom"]},"compBaseCents":{"type":["integer","null"]},"commissionBps":{"type":["integer","null"]},"amountCents":{"type":["integer","null"]},"partnerInvoicedCents":{"type":["integer","null"]},"partnerInvoicedShared":{"type":"boolean"},"sharedFields":{},"sharedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","dealId","dealName","partnerId","role","billingMode","compKind","compBase","compBaseCents","commissionBps","amountCents","partnerInvoicedCents","partnerInvoicedShared","sharedFields","sharedAt","createdAt"]},"DealPartnersCreate":{"type":"object","properties":{"dealId":{"type":"string","minLength":1},"partnerId":{"type":"string","minLength":1},"role":{"type":"string","enum":["referrer","subcontractor","reseller"]},"billingMode":{"type":"string","enum":["we_invoice","partner_invoices"]},"compKind":{"type":"string","enum":["commission_pct","fixed_amount","none"]},"compBase":{"type":"string","enum":["deal_total","agency_share","custom"]},"compBaseCents":{"anyOf":[{"type":"integer","minimum":0,"maximum":9007199254740991},{"type":"null"}]},"commissionBps":{"anyOf":[{"type":"integer","minimum":0,"maximum":1000000},{"type":"null"}]},"amountCents":{"anyOf":[{"type":"integer","minimum":0,"maximum":9007199254740991},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["dealId","partnerId","role"],"additionalProperties":false},"DealPartnersUpdate":{"type":"object","properties":{"role":{"type":"string","enum":["referrer","subcontractor","reseller"]},"billingMode":{"type":"string","enum":["we_invoice","partner_invoices"]},"compKind":{"type":"string","enum":["commission_pct","fixed_amount","none"]},"compBase":{"type":"string","enum":["deal_total","agency_share","custom"]},"compBaseCents":{"anyOf":[{"type":"integer","minimum":0,"maximum":9007199254740991},{"type":"null"}]},"commissionBps":{"anyOf":[{"type":"integer","minimum":0,"maximum":1000000},{"type":"null"}]},"amountCents":{"anyOf":[{"type":"integer","minimum":0,"maximum":9007199254740991},{"type":"null"}]}},"additionalProperties":false},"Suggestions":{"title":"Suggestions","type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"effort":{"type":["string","null"]},"benefit":{"type":["string","null"]},"status":{"type":"string"},"decisionNote":{"type":["string","null"]},"decidedAt":{"type":["string","null"],"format":"date-time"},"clientId":{"type":["string","null"]},"projectId":{"type":["string","null"]},"ticketId":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"}},"required":["id","title","description","effort","benefit","status","decisionNote","decidedAt","clientId","projectId","ticketId","createdAt"]},"GeoSettings":{"title":"AI visibility settings","type":"object","properties":{"id":{"type":"string"},"brand":{"type":"string"},"domain":{"type":["string","null"]},"aliases":{},"competitors":{},"country":{"type":"string"},"locale":{"type":"string"},"engines":{},"models":{},"frequency":{"type":"string"},"portalVisible":{"type":"boolean"},"enabled":{"type":"boolean"},"activatedAt":{"type":["string","null"],"format":"date-time"},"lastRunAt":{"type":["string","null"],"format":"date-time"},"lastError":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","brand","domain","aliases","competitors","country","locale","engines","models","frequency","portalVisible","enabled","activatedAt","lastRunAt","lastError","createdAt","updatedAt"]},"GeoSettingsCreate":{"type":"object","properties":{"brand":{"type":"string","minLength":1,"maxLength":120},"domain":{"anyOf":[{"type":"string","maxLength":253},{"type":"null"}]},"aliases":{"maxItems":25,"type":"array","items":{"type":"string","minLength":1,"maxLength":120}},"competitors":{"maxItems":25,"type":"array","items":{"type":"string","minLength":1,"maxLength":120}},"country":{"type":"string","minLength":2,"maxLength":2},"locale":{"type":"string","enum":["fr","en"]},"engines":{"minItems":1,"type":"array","items":{"type":"string","enum":["chatgpt","perplexity","gemini","claude","copilot","google_ai_overviews","google_ai_mode"]}},"models":{"type":"array","items":{"type":"string","enum":["claude","llama_4_scout","mistral_small_31","gpt_oss_120b","gemma_4_26b"]}},"frequency":{"type":"string","enum":["daily","weekly","monthly"]},"portalVisible":{"type":"boolean"},"clientId":{"type":"string"},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["brand","engines","clientId"],"additionalProperties":false},"GeoSettingsUpdate":{"type":"object","properties":{"brand":{"type":"string","minLength":1,"maxLength":120},"domain":{"anyOf":[{"type":"string","maxLength":253},{"type":"null"}]},"aliases":{"maxItems":25,"type":"array","items":{"type":"string","minLength":1,"maxLength":120}},"competitors":{"maxItems":25,"type":"array","items":{"type":"string","minLength":1,"maxLength":120}},"country":{"type":"string","minLength":2,"maxLength":2},"locale":{"type":"string","enum":["fr","en"]},"engines":{"minItems":1,"type":"array","items":{"type":"string","enum":["chatgpt","perplexity","gemini","claude","copilot","google_ai_overviews","google_ai_mode"]}},"models":{"type":"array","items":{"type":"string","enum":["claude","llama_4_scout","mistral_small_31","gpt_oss_120b","gemma_4_26b"]}},"frequency":{"type":"string","enum":["daily","weekly","monthly"]},"portalVisible":{"type":"boolean"}},"additionalProperties":false},"GeoPrompts":{"title":"AI visibility prompts","type":"object","properties":{"id":{"type":"string"},"text":{"type":"string"},"topic":{"type":["string","null"]},"active":{"type":"boolean"},"position":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","text","topic","active","position","createdAt","updatedAt"]},"GeoPromptsCreate":{"type":"object","properties":{"text":{"type":"string","minLength":3,"maxLength":500},"topic":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}]},"active":{"type":"boolean"},"position":{"type":"integer","minimum":0,"maximum":10000},"clientId":{"type":"string"},"createdAt":{"type":"string","format":"date-time","description":"When this actually happened, for an import. Past dates only; defaults to now. `updatedAt` follows it unless the body sets one."}},"required":["text","clientId"],"additionalProperties":false},"GeoPromptsUpdate":{"type":"object","properties":{"text":{"type":"string","minLength":3,"maxLength":500},"topic":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}]},"active":{"type":"boolean"},"position":{"type":"integer","minimum":0,"maximum":10000}},"additionalProperties":false},"ReviewRemarks":{"title":"Review remarks","type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string"},"body":{"type":"string"},"status":{"type":"string"},"reporterName":{"type":["string","null"]},"pageUrl":{"type":"string"},"pagePath":{"type":"string"},"pageTitle":{"type":["string","null"]},"selector":{"type":["string","null"]},"elementText":{"type":["string","null"]},"pageErrors":{},"release":{"type":["string","null"]},"screenshot":{"type":["string","null"]},"fixUrl":{"type":["string","null"]},"fixOpenedAt":{"type":["string","null"],"format":"date-time"},"siteName":{"type":["string","null"]},"repository":{"type":["string","null"]},"clientId":{"type":["string","null"]},"projectId":{"type":["string","null"]},"ticketId":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"}},"required":["id","kind","body","status","reporterName","pageUrl","pagePath","pageTitle","selector","elementText","pageErrors","release","screenshot","fixUrl","fixOpenedAt","siteName","repository","clientId","projectId","ticketId","createdAt"]},"ReviewSites":{"title":"Review sites","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"repository":{"type":["string","null"]},"allowedOrigins":{},"gate":{"type":"string"},"autoFile":{"type":"boolean"},"enabled":{"type":"boolean"},"expiresAt":{"type":"string","format":"date-time"},"clientId":{"type":["string","null"]},"projectId":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"}},"required":["id","name","repository","allowedOrigins","gate","autoFile","enabled","expiresAt","clientId","projectId","createdAt"]}},"responses":{"Unauthorized":{"description":"Missing, unknown or revoked key (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"Valid key, insufficient scope for this operation (`forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Unknown resource or id (`not_found`). An internal UUID is never a valid address — and a record belonging to another agency is reported the same way.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"InvalidRequest":{"description":"Malformed filter, sort or body (`invalid_request`). `details` lists what is accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"ValidationFailed":{"description":"Well-formed body, refused values (`validation_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"MethodNotAllowed":{"description":"The resource is read-only, or does not allow deletion (`method_not_allowed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Conflict":{"description":"The state forbids this right now (`conflict`). On a creating POST it means the `Idempotency-Key` was already used for a different body (`details.reason = idempotency_key_conflict`) or that the first call with it has not answered yet (`idempotency_key_in_flight`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"ServerError":{"description":"Internal incident (`server_error`), recorded in Sentry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Too fast (`details.reason = burst_limit`) or out of monthly tokens (`agency_quota_exhausted` / `user_quota_exhausted`). Both are fixed by waiting; `Retry-After` says how long.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}