{"openapi":"3.1.0","info":{"title":"EstateDraftFL firm API","version":"2026-10-01","description":"A firm's matters as ids, states and dates — never a name, a document's contents or a person's words. Every answer carries the verified-read triple (provenance_ids, provenance_count, verification.status) and as_of; an unreadable read answers 503, never an empty list. Nothing is executed: a key may at most file a proposal for the firm to decide."},"servers":[{"url":"https://estatedraftfl.com/api/v1"}],"components":{"securitySchemes":{"firmKey":{"type":"http","scheme":"bearer","bearerFormat":"edfl_live_…","description":"A firm's key, minted by its admin. Scopes: matters:read (Matters), deadlines:read (Deadlines), receipts:read (Receipts), documents:meta (Document facts), agenda:read (Agenda), capabilities:read (Capabilities), record:propose (Propose), webhooks:manage (Webhooks)."}},"schemas":{"Verification":{"type":"object","required":["status","method","counts","notes"],"properties":{"status":{"type":"string","enum":["unknown","ungrounded","grounded","verified"],"description":"The weakest of the answer's parts."},"method":{"type":"string"},"counts":{"type":"object","additionalProperties":{"type":["integer","null"]}},"notes":{"type":"array","items":{"type":"string"}}}},"Page":{"type":"object","required":["limit","has_more","next_cursor"],"properties":{"limit":{"type":"integer"},"has_more":{"type":"boolean","description":"True only when a further row exists — never a guess."},"next_cursor":{"type":["string","null"]}}},"ListEnvelope":{"type":"object","required":["ok","schema_version","generated_at","as_of","data","page","verification","provenance_ids","provenance_count"],"properties":{"ok":{"const":true},"schema_version":{"const":"2026-10-01"},"generated_at":{"type":"string","format":"date-time"},"as_of":{"type":"string","format":"date-time"},"data":{"type":["array","null"]},"page":{"$ref":"#/components/schemas/Page"},"verification":{"$ref":"#/components/schemas/Verification"},"provenance_ids":{"type":["array","null"],"items":{"type":"string"}},"provenance_count":{"type":["integer","null"]}}},"ItemEnvelope":{"type":"object","required":["ok","schema_version","generated_at","as_of","data","verification","provenance_ids","provenance_count"],"properties":{"ok":{"const":true},"schema_version":{"const":"2026-10-01"},"generated_at":{"type":"string","format":"date-time"},"as_of":{"type":"string","format":"date-time"},"data":{"type":"object"},"verification":{"$ref":"#/components/schemas/Verification"},"provenance_ids":{"type":"array","items":{"type":"string"}},"provenance_count":{"type":"integer"}}},"Error":{"type":"object","required":["ok","error","message"],"properties":{"ok":{"const":false},"error":{"type":"string"},"message":{"type":"string"},"field":{"type":["string","null"]},"scope":{"type":"string"},"retryable":{"type":"boolean"},"verification_status":{"type":"string"}}},"Matter":{"type":"object","required":["id","status","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"},"lifecycle":{"type":["string","null"]},"product":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"MatterDetail":{"allOf":[{"$ref":"#/components/schemas/Matter"},{"type":"object","properties":{"next_deadline_on":{"type":["string","null"],"format":"date","description":"Only for a key whose allowlist names the matter; null when it could not be read."},"open_requests":{"type":["integer","null"],"description":"Only for a key whose allowlist names the matter; null when it could not be read."},"documents":{"type":["object","null"],"description":"Only with documents:meta; null when it could not be read (never empty for unknown).","properties":{"view":{"type":"string","enum":["firm","client"]},"total":{"type":"integer"},"truncated":{"type":"boolean"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"sha256":{"type":["string","null"]},"scan_status":{"type":"string"},"upload_status":{"type":"string"},"uploaded_at":{"type":"string","format":"date-time"}}}}}}}}]},"Deadline":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"matter_id":{"type":"string","format":"uuid"},"task_key":{"type":"string"},"rule_key":{"type":"string"},"citation":{"type":"string"},"status":{"type":"string"},"due_on":{"type":["string","null"],"format":"date"},"calendarable":{"type":"boolean"},"confirmed_at":{"type":["string","null"],"format":"date-time"}}},"Receipt":{"type":"object","properties":{"id":{"type":"integer"},"matter_id":{"type":["string","null"],"format":"uuid"},"artifact_type":{"type":"string"},"content_hash":{"type":"string"},"prev_hash":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"}}},"AgendaItem":{"type":"object","properties":{"key":{"type":"string"},"kind":{"type":"string"},"register":{"type":"string"},"matter_id":{"type":["string","null"]},"dated":{"type":["string","null"]},"owner":{"type":"string"},"opened_at":{"type":"string"},"ethics_critical":{"type":"boolean"}}},"Capability":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"lane":{"type":"string"},"class":{"type":"string"},"status":{"type":"string"},"page":{"type":"string","format":"uri"}}},"ProposalInput":{"type":"object","required":["title"],"properties":{"title":{"type":"string","minLength":1,"maxLength":200},"detail":{"type":"string","maxLength":2000},"requested":{"type":"object","description":"Data only (a date, an amount) — at most 4 KB; never applied."}}},"ProposalFiled":{"type":"object","properties":{"ok":{"const":true},"id":{"type":"string","format":"uuid"},"status":{"const":"awaiting_firm"},"executed":{"const":false},"stripped":{"type":"array","items":{"type":"string"}},"message":{"type":"string"}}},"WebhookInput":{"type":"object","required":["url","events"],"properties":{"url":{"type":"string","format":"uri","pattern":"^https://","maxLength":2048},"events":{"type":"array","minItems":1,"uniqueItems":true,"items":{"type":"string","enum":["matter.status_changed","receipt.minted","deadline.confirmed","agenda.item_opened","transfer.requested","consult.received","approved_delivery.completed","source.changed","request.status_changed"]}},"description":{"type":"string","maxLength":200}}},"WebhookCreated":{"type":"object","properties":{"ok":{"const":true},"id":{"type":"string","format":"uuid"},"url":{"type":"string"},"events":{"type":"array","items":{"type":"string"}},"signing_secret":{"type":["string","null"],"description":"Shown once; null on a replay (secret_shown_once)."},"secret_shown_once":{"type":"boolean"},"message":{"type":"string"}}},"WebhookRotated":{"type":"object","properties":{"ok":{"const":true},"id":{"type":"string","format":"uuid"},"secret_version":{"type":"integer"},"signing_secret":{"type":["string","null"]},"secret_shown_once":{"type":"boolean"},"message":{"type":"string"}}},"WebhookTested":{"type":"object","properties":{"ok":{"const":true},"event_id":{"type":"string","format":"uuid"},"delivery":{"type":"string","enum":["delivered","failed","queued"]},"message":{"type":"string"}}},"WebhookList":{"type":"object","properties":{"ok":{"const":true},"schema_version":{"const":"2026-10-01"},"generated_at":{"type":"string"},"data":{"type":"array","items":{"type":"object"}}}},"Done":{"type":"object","properties":{"ok":{"const":true},"id":{"type":"string"},"message":{"type":"string"}}}}},"paths":{"/matters":{"get":{"operationId":"listMatters","summary":"The firm's matters","description":"Newest first; ids, states and dates only. A matter with a wall is never listed or counted. Default page 200 (the v1 contract), maximum 200.","security":[{"firmKey":["matters:read"]}],"x-scope":"matters:read","x-rate-lane":"read","x-client-safe":true,"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":200},"description":"Page size, 1–200. Anything else is refused (400), never clamped."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"The next_cursor of a previous page, unchanged. A position only — every page is authorized again."}],"responses":{"200":{"description":"A page of matters.","headers":{"RateLimit-Limit":{"schema":{"type":"integer"},"description":"The lane's requests per window."},"RateLimit-Remaining":{"schema":{"type":"integer"},"description":"What is left of it in this window."},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until the window turns over (exact: windows are aligned to the epoch)."},"RateLimit-Policy":{"schema":{"type":"string"},"description":"e.g. 120;w=60."},"X-RateLimit-Enforcement":{"schema":{"type":"string","enum":["global"]},"description":"The windows are one database's, shared by every server instance."}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":["array","null"],"items":{"$ref":"#/components/schemas/Matter"}}}}]}}}},"400":{"description":"Refused: a parameter, the body or the Idempotency-Key could not be read (the field is named).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The key is missing, unknown, revoked or expired — the same answer for each.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not hold the scope (named), or its sensitivity may never hold it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The key's rate lane is spent — Retry-After and RateLimit-Reset say when it refills.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The read or write could not be completed — retryable; nothing is known about the result (never an empty list).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/matters/{id}":{"get":{"operationId":"getMatter","summary":"One matter","description":"The same 404 for an unknown id and one the key may not read. Richer for a key whose allowlist names the matter; documents only with documents:meta.","security":[{"firmKey":["matters:read"]}],"x-scope":"matters:read","x-rate-lane":"read","x-client-safe":true,"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The matter.","headers":{"RateLimit-Limit":{"schema":{"type":"integer"},"description":"The lane's requests per window."},"RateLimit-Remaining":{"schema":{"type":"integer"},"description":"What is left of it in this window."},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until the window turns over (exact: windows are aligned to the epoch)."},"RateLimit-Policy":{"schema":{"type":"string"},"description":"e.g. 120;w=60."},"X-RateLimit-Enforcement":{"schema":{"type":"string","enum":["global"]},"description":"The windows are one database's, shared by every server instance."}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ItemEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MatterDetail"}}}]}}}},"401":{"description":"The key is missing, unknown, revoked or expired — the same answer for each.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not hold the scope (named), or its sensitivity may never hold it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found — the same answer for an unknown id and one the key may not read.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The key's rate lane is spent — Retry-After and RateLimit-Reset say when it refills.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The read or write could not be completed — retryable; nothing is known about the result (never an empty list).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/matters/{id}/proposals":{"post":{"operationId":"proposeAction","summary":"Propose an action for the firm to decide","description":"Files a proposal; nothing is executed (executed: false). Fields beyond title, detail and requested are stripped and named on the firm's card. Three undecided per matter.","security":[{"firmKey":["record:propose"]}],"x-scope":"record:propose","x-rate-lane":"write","x-client-safe":false,"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"Required on every write. The same key with the same request replays the first answer (Idempotent-Replayed: true); with a different request it is refused (409). Kept 24 hours."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProposalInput"}}}},"responses":{"201":{"description":"Filed, awaiting the firm.","headers":{"RateLimit-Limit":{"schema":{"type":"integer"},"description":"The lane's requests per window."},"RateLimit-Remaining":{"schema":{"type":"integer"},"description":"What is left of it in this window."},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until the window turns over (exact: windows are aligned to the epoch)."},"RateLimit-Policy":{"schema":{"type":"string"},"description":"e.g. 120;w=60."},"X-RateLimit-Enforcement":{"schema":{"type":"string","enum":["global"]},"description":"The windows are one database's, shared by every server instance."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProposalFiled"}}}},"400":{"description":"Refused: a parameter, the body or the Idempotency-Key could not be read (the field is named).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The key is missing, unknown, revoked or expired — the same answer for each.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not hold the scope (named), or its sensitivity may never hold it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found — the same answer for an unknown id and one the key may not read.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A conflict: an Idempotency-Key reused with a different request, a write still running (retry), or the record's state refuses it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The key's rate lane is spent — Retry-After and RateLimit-Reset say when it refills.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The read or write could not be completed — retryable; nothing is known about the result (never an empty list).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/deadlines":{"get":{"operationId":"listDeadlines","summary":"The firm's derived deadlines","description":"Each with its rule key, its citation, its status and whether it was confirmed.","security":[{"firmKey":["deadlines:read"]}],"x-scope":"deadlines:read","x-rate-lane":"read","x-client-safe":false,"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"description":"Page size, 1–200. Anything else is refused (400), never clamped."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"The next_cursor of a previous page, unchanged. A position only — every page is authorized again."}],"responses":{"200":{"description":"A page of deadlines.","headers":{"RateLimit-Limit":{"schema":{"type":"integer"},"description":"The lane's requests per window."},"RateLimit-Remaining":{"schema":{"type":"integer"},"description":"What is left of it in this window."},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until the window turns over (exact: windows are aligned to the epoch)."},"RateLimit-Policy":{"schema":{"type":"string"},"description":"e.g. 120;w=60."},"X-RateLimit-Enforcement":{"schema":{"type":"string","enum":["global"]},"description":"The windows are one database's, shared by every server instance."}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":["array","null"],"items":{"$ref":"#/components/schemas/Deadline"}}}}]}}}},"400":{"description":"Refused: a parameter, the body or the Idempotency-Key could not be read (the field is named).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The key is missing, unknown, revoked or expired — the same answer for each.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not hold the scope (named), or its sensitivity may never hold it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The key's rate lane is spent — Retry-After and RateLimit-Reset say when it refills.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The read or write could not be completed — retryable; nothing is known about the result (never an empty list).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/receipts":{"get":{"operationId":"listReceipts","summary":"The firm's receipts","description":"Each receipt's type, content hash and the previous receipt's hash — verifiable at https://estatedraftfl.com/verify.","security":[{"firmKey":["receipts:read"]}],"x-scope":"receipts:read","x-rate-lane":"read","x-client-safe":true,"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"description":"Page size, 1–200. Anything else is refused (400), never clamped."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"The next_cursor of a previous page, unchanged. A position only — every page is authorized again."}],"responses":{"200":{"description":"A page of receipts.","headers":{"RateLimit-Limit":{"schema":{"type":"integer"},"description":"The lane's requests per window."},"RateLimit-Remaining":{"schema":{"type":"integer"},"description":"What is left of it in this window."},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until the window turns over (exact: windows are aligned to the epoch)."},"RateLimit-Policy":{"schema":{"type":"string"},"description":"e.g. 120;w=60."},"X-RateLimit-Enforcement":{"schema":{"type":"string","enum":["global"]},"description":"The windows are one database's, shared by every server instance."}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":["array","null"],"items":{"$ref":"#/components/schemas/Receipt"}}}}]}}}},"400":{"description":"Refused: a parameter, the body or the Idempotency-Key could not be read (the field is named).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The key is missing, unknown, revoked or expired — the same answer for each.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not hold the scope (named), or its sensitivity may never hold it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The key's rate lane is spent — Retry-After and RateLimit-Reset say when it refills.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The read or write could not be completed — retryable; nothing is known about the result (never an empty list).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agenda":{"get":{"operationId":"getAgenda","summary":"What waits on the firm","description":"The firm's agenda by kind and register — never a name. A lane that could not be read lowers the status to unknown and is named in the notes.","security":[{"firmKey":["agenda:read"]}],"x-scope":"agenda:read","x-rate-lane":"read","x-client-safe":false,"responses":{"200":{"description":"The agenda.","headers":{"RateLimit-Limit":{"schema":{"type":"integer"},"description":"The lane's requests per window."},"RateLimit-Remaining":{"schema":{"type":"integer"},"description":"What is left of it in this window."},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until the window turns over (exact: windows are aligned to the epoch)."},"RateLimit-Policy":{"schema":{"type":"string"},"description":"e.g. 120;w=60."},"X-RateLimit-Enforcement":{"schema":{"type":"string","enum":["global"]},"description":"The windows are one database's, shared by every server instance."}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":["array","null"],"items":{"$ref":"#/components/schemas/AgendaItem"}}}}]}}}},"401":{"description":"The key is missing, unknown, revoked or expired — the same answer for each.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not hold the scope (named), or its sensitivity may never hold it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The key's rate lane is spent — Retry-After and RateLimit-Reset say when it refills.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The read or write could not be completed — retryable; nothing is known about the result (never an empty list).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/capabilities":{"get":{"operationId":"listCapabilities","summary":"The platform's capabilities","description":"The published capability catalogue.","security":[{"firmKey":["capabilities:read"]}],"x-scope":"capabilities:read","x-rate-lane":"read","x-client-safe":true,"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"description":"Page size, 1–200. Anything else is refused (400), never clamped."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"The next_cursor of a previous page, unchanged. A position only — every page is authorized again."}],"responses":{"200":{"description":"A page of capabilities.","headers":{"RateLimit-Limit":{"schema":{"type":"integer"},"description":"The lane's requests per window."},"RateLimit-Remaining":{"schema":{"type":"integer"},"description":"What is left of it in this window."},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until the window turns over (exact: windows are aligned to the epoch)."},"RateLimit-Policy":{"schema":{"type":"string"},"description":"e.g. 120;w=60."},"X-RateLimit-Enforcement":{"schema":{"type":"string","enum":["global"]},"description":"The windows are one database's, shared by every server instance."}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":["array","null"],"items":{"$ref":"#/components/schemas/Capability"}}}}]}}}},"400":{"description":"Refused: a parameter, the body or the Idempotency-Key could not be read (the field is named).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The key is missing, unknown, revoked or expired — the same answer for each.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not hold the scope (named), or its sensitivity may never hold it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The key's rate lane is spent — Retry-After and RateLimit-Reset say when it refills.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The read or write could not be completed — retryable; nothing is known about the result (never an empty list).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks":{"get":{"operationId":"listWebhooks","summary":"The firm's webhook endpoints","description":"Each endpoint with its ten latest delivery attempts (status code, duration, the class of a failure — never a response body).","security":[{"firmKey":["webhooks:manage"]}],"x-scope":"webhooks:manage","x-rate-lane":"read","x-client-safe":false,"responses":{"200":{"description":"The endpoints.","headers":{"RateLimit-Limit":{"schema":{"type":"integer"},"description":"The lane's requests per window."},"RateLimit-Remaining":{"schema":{"type":"integer"},"description":"What is left of it in this window."},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until the window turns over (exact: windows are aligned to the epoch)."},"RateLimit-Policy":{"schema":{"type":"string"},"description":"e.g. 120;w=60."},"X-RateLimit-Enforcement":{"schema":{"type":"string","enum":["global"]},"description":"The windows are one database's, shared by every server instance."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookList"}}}},"401":{"description":"The key is missing, unknown, revoked or expired — the same answer for each.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not hold the scope (named), or its sensitivity may never hold it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The key's rate lane is spent — Retry-After and RateLimit-Reset say when it refills.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The read or write could not be completed — retryable; nothing is known about the result (never an empty list).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createWebhook","summary":"Register a webhook endpoint","description":"An https address on the public internet and its events. The signing secret is in this answer once and never again (a replay says so).","security":[{"firmKey":["webhooks:manage"]}],"x-scope":"webhooks:manage","x-rate-lane":"write","x-client-safe":false,"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"Required on every write. The same key with the same request replays the first answer (Idempotent-Replayed: true); with a different request it is refused (409). Kept 24 hours."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookInput"}}}},"responses":{"201":{"description":"Registered.","headers":{"RateLimit-Limit":{"schema":{"type":"integer"},"description":"The lane's requests per window."},"RateLimit-Remaining":{"schema":{"type":"integer"},"description":"What is left of it in this window."},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until the window turns over (exact: windows are aligned to the epoch)."},"RateLimit-Policy":{"schema":{"type":"string"},"description":"e.g. 120;w=60."},"X-RateLimit-Enforcement":{"schema":{"type":"string","enum":["global"]},"description":"The windows are one database's, shared by every server instance."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookCreated"}}}},"400":{"description":"Refused: a parameter, the body or the Idempotency-Key could not be read (the field is named).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The key is missing, unknown, revoked or expired — the same answer for each.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not hold the scope (named), or its sensitivity may never hold it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A conflict: an Idempotency-Key reused with a different request, a write still running (retry), or the record's state refuses it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The key's rate lane is spent — Retry-After and RateLimit-Reset say when it refills.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The read or write could not be completed — retryable; nothing is known about the result (never an empty list).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks/{id}":{"delete":{"operationId":"disableWebhook","summary":"Disable a webhook endpoint","description":"With the reason ({ \"reason\": \"…\" }). Its secret is destroyed; the endpoint is kept as a record.","security":[{"firmKey":["webhooks:manage"]}],"x-scope":"webhooks:manage","x-rate-lane":"write","x-client-safe":false,"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"Required on every write. The same key with the same request replays the first answer (Idempotent-Replayed: true); with a different request it is refused (409). Kept 24 hours."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":300}},"required":["reason"]}}}},"responses":{"200":{"description":"Disabled.","headers":{"RateLimit-Limit":{"schema":{"type":"integer"},"description":"The lane's requests per window."},"RateLimit-Remaining":{"schema":{"type":"integer"},"description":"What is left of it in this window."},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until the window turns over (exact: windows are aligned to the epoch)."},"RateLimit-Policy":{"schema":{"type":"string"},"description":"e.g. 120;w=60."},"X-RateLimit-Enforcement":{"schema":{"type":"string","enum":["global"]},"description":"The windows are one database's, shared by every server instance."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Done"}}}},"400":{"description":"Refused: a parameter, the body or the Idempotency-Key could not be read (the field is named).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The key is missing, unknown, revoked or expired — the same answer for each.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not hold the scope (named), or its sensitivity may never hold it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found — the same answer for an unknown id and one the key may not read.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A conflict: an Idempotency-Key reused with a different request, a write still running (retry), or the record's state refuses it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The key's rate lane is spent — Retry-After and RateLimit-Reset say when it refills.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The read or write could not be completed — retryable; nothing is known about the result (never an empty list).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks/{id}/test":{"post":{"operationId":"testWebhook","summary":"Send a test event","description":"Fictional data (data.test: true), signed like any other and delivered at once: the answer says whether the receiver took it.","security":[{"firmKey":["webhooks:manage"]}],"x-scope":"webhooks:manage","x-rate-lane":"write","x-client-safe":false,"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"Required on every write. The same key with the same request replays the first answer (Idempotent-Replayed: true); with a different request it is refused (409). Kept 24 hours."}],"responses":{"200":{"description":"Sent (or queued).","headers":{"RateLimit-Limit":{"schema":{"type":"integer"},"description":"The lane's requests per window."},"RateLimit-Remaining":{"schema":{"type":"integer"},"description":"What is left of it in this window."},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until the window turns over (exact: windows are aligned to the epoch)."},"RateLimit-Policy":{"schema":{"type":"string"},"description":"e.g. 120;w=60."},"X-RateLimit-Enforcement":{"schema":{"type":"string","enum":["global"]},"description":"The windows are one database's, shared by every server instance."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTested"}}}},"401":{"description":"The key is missing, unknown, revoked or expired — the same answer for each.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not hold the scope (named), or its sensitivity may never hold it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found — the same answer for an unknown id and one the key may not read.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A conflict: an Idempotency-Key reused with a different request, a write still running (retry), or the record's state refuses it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The key's rate lane is spent — Retry-After and RateLimit-Reset say when it refills.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The read or write could not be completed — retryable; nothing is known about the result (never an empty list).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks/{id}/rotate":{"post":{"operationId":"rotateWebhookSecret","summary":"Rotate an endpoint's signing secret","description":"The old secret is destroyed at once; the new one is in this answer once.","security":[{"firmKey":["webhooks:manage"]}],"x-scope":"webhooks:manage","x-rate-lane":"write","x-client-safe":false,"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"Required on every write. The same key with the same request replays the first answer (Idempotent-Replayed: true); with a different request it is refused (409). Kept 24 hours."}],"responses":{"200":{"description":"Rotated.","headers":{"RateLimit-Limit":{"schema":{"type":"integer"},"description":"The lane's requests per window."},"RateLimit-Remaining":{"schema":{"type":"integer"},"description":"What is left of it in this window."},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until the window turns over (exact: windows are aligned to the epoch)."},"RateLimit-Policy":{"schema":{"type":"string"},"description":"e.g. 120;w=60."},"X-RateLimit-Enforcement":{"schema":{"type":"string","enum":["global"]},"description":"The windows are one database's, shared by every server instance."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookRotated"}}}},"401":{"description":"The key is missing, unknown, revoked or expired — the same answer for each.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key does not hold the scope (named), or its sensitivity may never hold it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found — the same answer for an unknown id and one the key may not read.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A conflict: an Idempotency-Key reused with a different request, a write still running (retry), or the record's state refuses it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The key's rate lane is spent — Retry-After and RateLimit-Reset say when it refills.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The read or write could not be completed — retryable; nothing is known about the result (never an empty list).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/openapi.json":{"get":{"operationId":"openApi","summary":"This document","description":"The OpenAPI 3.1 description of the firm API v1. No key needed.","security":[],"responses":{"200":{"description":"The OpenAPI document.","content":{"application/json":{"schema":{"type":"object"}}}}}}}},"x-webhook-events":["matter.status_changed","receipt.minted","deadline.confirmed","agenda.item_opened","transfer.requested","consult.received","approved_delivery.completed","source.changed","request.status_changed"]}