{"openapi":"3.1.0","info":{"title":"Guliel API","version":"1.0.0","description":"Manage, automate, and run every financial operation of your business — or many businesses — programmatically. The Guliel API exposes the full surface of the platform so you (and the agents, apps, and integrations you build) can connect seamlessly: issue tax-compliant invoices, receipts, credit and debit memos; ingest and reconcile expenses with OCR and email scanning; manage customers, suppliers, purchase orders, inventory and stock movements; run income, expense, AR-aging and tax reports; wire up bank accounts and tax-authority clearance integrations; and orchestrate multi-tenant organizations, users, roles, and notifications. Built for global, multi-currency, multi-jurisdiction businesses with country-specific tax handling (Israel, Singapore, USA today, growing). Every endpoint is also available as an MCP tool so AI agents can drive the same actions a human would in the dashboard. Authentication uses Bearer API keys (OAuth 2.0 for third-party apps); responses are JSON; errors carry stable machine-readable codes. Use this API for: invoicing automation, expense automation, accounts-receivable, accounts-payable, e-invoicing, tax compliance, financial reporting, ERP and accounting integrations, and AI-driven bookkeeping agents.","contact":{"name":"Guliel","url":"https://guliel.com/docs/api","email":"hello@guliel.com"}},"servers":[{"url":"https://guliel.com/api","description":"Production"}],"tags":[{"name":"invoices","description":"Document creation, sending, and payment tracking. Covers invoices, receipts, payment requests, credit/debit memos, and clearance flows for jurisdictions that require it.","x-display-order":0},{"name":"payments","description":"Settlement recording and allocation across document lines, including partial and multi-document payments.","x-display-order":1},{"name":"expenses","description":"Expense logging, OCR scanning, email ingestion, vendor matching, and approval workflow.","x-display-order":2},{"name":"customers","description":"Customer records (external and in-system suppliers' clients), recipients for invoice delivery.","x-display-order":3},{"name":"suppliers","description":"Supplier directory, cross-org invitations, accepted supplier catalogs.","x-display-order":4},{"name":"orders","description":"Purchase orders from clients to suppliers, including the supplier-side reverse view.","x-display-order":5},{"name":"logistics","description":"Item catalog, stock levels, and stock-movement audit trail.","x-display-order":6},{"name":"reports","description":"Pre-built and country-specific financial reports — income, expenses, AR aging, tax compliance.","x-display-order":7},{"name":"bank_accounts","description":"Banking details for invoice payment instructions.","x-display-order":8},{"name":"organizations","description":"Tenant management — create, configure, manage org-level settings and tax-authority integrations.","x-display-order":9},{"name":"users","description":"Org membership, role management, invitations, and notifications.","x-display-order":10},{"name":"automations","description":"Scheduled and triggered workflows — wire any platform event to any API action. An automation is a graph of TRIGGER/FILTER/ACTION blocks joined by edges: discover the block catalog (GET /api/automations/actions), create the graph in DRAFT, test it synchronously, then enable it to arm.","x-display-order":11},{"name":"integrations","description":"Email inbox connections (Gmail/Outlook/IMAP/POP3) and tax-authority credential management.","x-display-order":12},{"name":"settings","description":"Caller's own preferences and platform utilities (e.g. exchange-rate refresh).","x-display-order":13},{"name":"companion","description":"","x-display-order":14}],"paths":{"/api/api-keys":{"get":{"tags":["users"],"summary":"List API keys","description":"Lists API keys the caller can see. Results are filtered by the caller's accessible organizations; many routes paginate via `page` and `limit`.\n\n**Scope:** `users:read`  \n**Auth sources:** `SESSION` only  \n**Endpoint:** `GET /api/api-keys`","operationId":"api_keys.api_keys","parameters":[],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"keys":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"prefix":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"allOrgs":{"type":"boolean"},"organizationIds":{"type":"array","items":{"type":"string"}},"expiresAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastUsedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"revokedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"}},"required":["id","name","prefix","scopes","allOrgs","organizationIds","expiresAt","lastUsedAt","revokedAt","createdAt"],"additionalProperties":false}}},"required":["keys"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:read"]}],"x-guliel-feature":"users","x-guliel-verb":"read","x-guliel-allowed-sources":["SESSION"],"x-guliel-scope":"users:read"},"post":{"tags":["users"],"summary":"Create an API key","description":"Creates a new API key in the target organization. Returns the created record on success.\n\n**Scope:** `users:write`  \n**Auth sources:** `SESSION` only  \n**Endpoint:** `POST /api/api-keys`","operationId":"api_keys.api_keys","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80},"scopes":{"minItems":1,"maxItems":50,"type":"array","items":{"type":"string","pattern":"^(\\*|invoices|expenses|customers|suppliers|orders|logistics|reports|bank_accounts|organizations|users|automations|integrations|settings):(read|write|\\*)$"}},"allOrgs":{"default":false,"type":"boolean"},"organizationIds":{"type":"array","items":{"type":"string"}},"expiresAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]}},"required":["name","scopes","allOrgs"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"key":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"prefix":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"allOrgs":{"type":"boolean"},"organizationIds":{"type":"array","items":{"type":"string"}},"expiresAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastUsedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"revokedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"}},"required":["id","name","prefix","scopes","allOrgs","organizationIds","expiresAt","lastUsedAt","revokedAt","createdAt"],"additionalProperties":false},"secret":{"type":"string"}},"required":["key","secret"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"key":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"prefix":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"allOrgs":{"type":"boolean"},"organizationIds":{"type":"array","items":{"type":"string"}},"expiresAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastUsedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"revokedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"}},"required":["id","name","prefix","scopes","allOrgs","organizationIds","expiresAt","lastUsedAt","revokedAt","createdAt"],"additionalProperties":false},"secret":{"type":"string"}},"required":["key","secret"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:write"]}],"x-guliel-feature":"users","x-guliel-verb":"write","x-guliel-allowed-sources":["SESSION"],"x-guliel-scope":"users:write"}},"/api/api-keys/{id}":{"get":{"tags":["users"],"summary":"Get an API key","description":"Fetches a single API key by id. Returns 404 if the API key isn't in the caller's accessible organizations.\n\n**Scope:** `users:read`  \n**Auth sources:** `SESSION` only  \n**Endpoint:** `GET /api/api-keys/{id}`","operationId":"api_keys.get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"key":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"prefix":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"allOrgs":{"type":"boolean"},"organizationIds":{"type":"array","items":{"type":"string"}},"expiresAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastUsedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"revokedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"}},"required":["id","name","prefix","scopes","allOrgs","organizationIds","expiresAt","lastUsedAt","revokedAt","createdAt"],"additionalProperties":false}},"required":["key"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:read"]}],"x-guliel-feature":"users","x-guliel-verb":"read","x-guliel-allowed-sources":["SESSION"],"x-guliel-scope":"users:read"},"patch":{"tags":["users"],"summary":"Update an API key","description":"Updates an existing API key. Only the fields present in the request body are changed; omitted fields stay as-is.\n\n**Scope:** `users:write`  \n**Auth sources:** `SESSION` only  \n**Endpoint:** `PATCH /api/api-keys/{id}`","operationId":"api_keys.update","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","minLength":1,"maxLength":80},"expiresAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"key":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"prefix":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"allOrgs":{"type":"boolean"},"organizationIds":{"type":"array","items":{"type":"string"}},"expiresAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"lastUsedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"revokedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"}},"required":["id","name","prefix","scopes","allOrgs","organizationIds","expiresAt","lastUsedAt","revokedAt","createdAt"],"additionalProperties":false}},"required":["key"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:write"]}],"x-guliel-feature":"users","x-guliel-verb":"write","x-guliel-allowed-sources":["SESSION"],"x-guliel-scope":"users:write"},"delete":{"tags":["users"],"summary":"Delete an API key","description":"Deletes the API key. Some endpoints hard-delete the row, others soft-revoke (set `revokedAt`). Check the response shape.\n\n**Scope:** `users:write`  \n**Auth sources:** `SESSION` only  \n**Endpoint:** `DELETE /api/api-keys/{id}`","operationId":"api_keys.delete","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"revokedAt":{"type":"string"}},"required":["revokedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:write"]}],"x-guliel-feature":"users","x-guliel-verb":"write","x-guliel-allowed-sources":["SESSION"],"x-guliel-scope":"users:write"}},"/api/api-keys/{id}/usage":{"get":{"tags":["users"],"summary":"API key usage history","description":"Returns the caller's recent request log for the API key (last 7 days by default).\n\n**Scope:** `users:read`  \n**Auth sources:** `SESSION` only  \n**Endpoint:** `GET /api/api-keys/{id}/usage`","operationId":"api_keys.usage","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."},{"name":"limit","in":"query","required":true,"schema":{"default":50,"type":"integer","minimum":1,"maximum":200}},{"name":"sinceDays","in":"query","required":true,"schema":{"default":7,"type":"integer","minimum":1,"maximum":365}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"totals":{"type":"object","properties":{"callCount":{"type":"number"},"errorCount":{"type":"number"},"avgDurationMs":{"anyOf":[{"type":"number"},{"type":"null"}]}},"required":["callCount","errorCount","avgDurationMs"],"additionalProperties":false},"byFeature":{"type":"array","items":{"type":"object","properties":{"feature":{"anyOf":[{"type":"string"},{"type":"null"}]},"calls":{"type":"number"},"errors":{"type":"number"}},"required":["feature","calls","errors"],"additionalProperties":false}},"recent":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"method":{"type":"string"},"path":{"type":"string"},"feature":{"anyOf":[{"type":"string"},{"type":"null"}]},"verb":{"anyOf":[{"type":"string"},{"type":"null"}]},"statusCode":{"type":"number"},"errorCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"durationMs":{"type":"number"},"organizationId":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"}},"required":["id","method","path","feature","verb","statusCode","errorCode","durationMs","organizationId","createdAt"],"additionalProperties":false}}},"required":["totals","byFeature","recent"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:read"]}],"x-guliel-feature":"users","x-guliel-verb":"read","x-guliel-allowed-sources":["SESSION"],"x-guliel-scope":"users:read"}},"/api/automations":{"get":{"tags":["automations"],"summary":"List automations","description":"Lists automations the caller can see. Results are filtered by the caller's accessible organizations; many routes paginate via `page` and `limit`.\n\n**Scope:** `automations:read`  \n**Endpoint:** `GET /api/automations`","operationId":"automations.automations","parameters":[{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["DRAFT","ENABLED","PAUSED","PAUSED_NO_ACCESS"]}},{"name":"page","in":"query","required":true,"schema":{"default":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"name":"limit","in":"query","required":true,"schema":{"default":20,"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"automations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"ownerUserId":{"type":"string","description":"The run-as identity: when the automation fires, actions execute under this user's current org permissions."},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["DRAFT","ENABLED","PAUSED","PAUSED_NO_ACCESS"],"description":"DRAFT = never armed; ENABLED = armed (fires on its trigger; the free tier allows 5 enabled per org); PAUSED = manually disarmed; PAUSED_NO_ACCESS = auto-paused because the owner lost the required org access."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"blocks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Client-chosen id, unique within the automation. Edges reference blocks by this id, and downstream blocks read this block's output via {{blocks.<id>.…}} bindings."},"kind":{"type":"string","enum":["TRIGGER","FILTER","ACTION","CUSTOM"],"description":"TRIGGER starts the flow when its event fires (every automation needs at least one); FILTER queries org data and outputs a shaped list/value; ACTION invokes a tool; CUSTOM is reserved and not executable in v1."},"ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What the block invokes. TRIGGER: an event type from the catalog, e.g. \"invoice.paid\" or \"schedule.daily\" (GET /api/automations/actions lists them). ACTION: an MCP tool name, e.g. \"invoices.send\", or engine-native \"webhook.post\" / \"email.send\". FILTER: omit — the query lives in config.spec."},"config":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Kind-specific configuration. ACTION: { input: { … } } — the arguments for the tool named by ref, matching that tool's inputSchema from the catalog; values may embed {{…}} bindings ({{trigger.*}}, {{blocks.<id>.*}}, {{item.*}} under a FOR_EACH edge, {{context.now}}, {{context.today}}, {{context.orgId}}) — a whole-string binding like \"{{trigger.total}}\" keeps the value's native type, inline bindings interpolate into the string. FILTER: { spec: { root, follows?, predicates?, aggregateBy?, extract, shape? } } over the served filter catalog. TRIGGER: ignored."},"position":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Editor canvas hint ({ x, y }). Ignored by the engine."}},"required":["id","kind","ref","config","position"],"additionalProperties":false}},"edges":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Client-chosen id, unique within the automation."},"fromBlockId":{"type":"string","description":"Id of the source block. The graph must be a DAG — self-loops and cycles are rejected."},"toBlockId":{"type":"string","description":"Id of the target block. The target runs only after the source step succeeds and the cond (if any) passes."},"cond":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}],"description":"Optional guard — null/omitted means the edge is always followed. Leaf: { left, op, right? } with op one of eq | ne | gt | gte | lt | lte | in | nin | contains | exists | empty; compose with { all: […] }, { any: […] }, { not: … }. Operands may be literals or {{…}} bindings; comparisons are type-light (100 equals \"100\")."},"mode":{"type":"string","enum":["ONCE","FOR_EACH"],"description":"ONCE (default) passes the source output downstream as-is; FOR_EACH fans a list-valued source output out, running the target once per element (exposed as {{item.*}}) — a non-list source falls back to a single run."},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Display ordering only — execution order is topological."}},"required":["id","fromBlockId","toBlockId","cond","mode","order"],"additionalProperties":false}}},"required":["id","organizationId","ownerUserId","name","description","status","createdAt","updatedAt"],"additionalProperties":false}},"pagination":{"type":"object","properties":{"page":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"totalPages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["page","limit","total","totalPages"],"additionalProperties":false}},"required":["automations","pagination"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["automations:read"]}],"x-guliel-feature":"automations","x-guliel-verb":"read","x-guliel-scope":"automations:read"},"post":{"tags":["automations"],"summary":"Create an automation","description":"Creates a new automation in the target organization. Returns the created record on success.\n\nAn automation is a **graph**: blocks (nodes) joined by edges. One `TRIGGER` block starts the flow when its event fires; `ACTION` blocks do the work; optional `FILTER` blocks query org data in between. Discover the building blocks from `GET /api/automations/actions`: trigger event types (each with the payload fields available to `{{trigger.*}}` bindings), the action tool catalog (each with its input schema), and the filterable objects for FILTER specs.\n\n**Lifecycle.** Created in `DRAFT` — it does not fire yet. Verify it synchronously with `POST /api/automations/{id}/test`, then arm it with `POST /api/automations/{id}/enable` (free tier: 5 enabled automations per org). Once enabled, it runs with the **owner's** permissions, resolved at fire time; an action the owner can't perform fails the run and auto-pauses the automation (`PAUSED_NO_ACCESS`).\n\n**Example — email on every paid invoice:**\n\n```json\n{\n  \"organizationId\": \"org_123\",\n  \"name\": \"Email me when an invoice is paid\",\n  \"blocks\": [\n    { \"id\": \"t1\", \"kind\": \"TRIGGER\", \"ref\": \"invoice.paid\" },\n    {\n      \"id\": \"a1\",\n      \"kind\": \"ACTION\",\n      \"ref\": \"email.send\",\n      \"config\": {\n        \"input\": {\n          \"to\": \"ops@example.com\",\n          \"subject\": \"Invoice {{trigger.id}} paid\",\n          \"body\": \"Amount: {{trigger.total}} {{trigger.currency}}\"\n        }\n      }\n    }\n  ],\n  \"edges\": [{ \"id\": \"e1\", \"fromBlockId\": \"t1\", \"toBlockId\": \"a1\" }]\n}\n```\n\n**Bindings.** Action inputs, filter predicate values, and edge-condition operands may embed `{{…}}` paths resolved at run time: `{{trigger.*}}` (the event payload), `{{blocks.<blockId>.*}}` (an upstream block's output), `{{item.*}}` (the current element, under a `FOR_EACH` edge), and `{{context.now}}` / `{{context.today}}` / `{{context.orgId}}`. A whole-string binding (`\"{{trigger.total}}\"`) keeps the value's native type; inline bindings interpolate into the string.\n\n**Example — monthly digest of overdue receivables, one webhook call per document.** The FILTER block's `config.spec` selects and shapes rows; the `FOR_EACH` edge fans the list out, one ACTION step per element:\n\n```json\n{\n  \"organizationId\": \"org_123\",\n  \"name\": \"Monthly overdue digest\",\n  \"blocks\": [\n    { \"id\": \"t1\", \"kind\": \"TRIGGER\", \"ref\": \"schedule.monthly\" },\n    {\n      \"id\": \"f1\",\n      \"kind\": \"FILTER\",\n      \"config\": {\n        \"spec\": {\n          \"root\": \"Document\",\n          \"predicates\": [\n            { \"object\": \"Document\", \"field\": \"status\", \"op\": \"ne\", \"value\": \"PAID\" },\n            { \"object\": \"Document\", \"field\": \"direction\", \"op\": \"eq\", \"value\": \"OUTGOING\" },\n            { \"object\": \"Document\", \"field\": \"dueDate\", \"op\": \"lt\", \"value\": \"{{context.today}}\" }\n          ],\n          \"extract\": [\n            { \"as\": \"documentId\", \"path\": \"Document.id\" },\n            { \"as\": \"number\", \"path\": \"Document.invoiceNumber\" },\n            { \"as\": \"amountDue\", \"path\": \"Document.total\" }\n          ],\n          \"shape\": \"objects\"\n        }\n      }\n    },\n    {\n      \"id\": \"a1\",\n      \"kind\": \"ACTION\",\n      \"ref\": \"webhook.post\",\n      \"config\": {\n        \"input\": {\n          \"url\": \"https://example.com/hooks/overdue\",\n          \"body\": { \"id\": \"{{item.documentId}}\", \"number\": \"{{item.number}}\", \"due\": \"{{item.amountDue}}\" }\n        }\n      }\n    }\n  ],\n  \"edges\": [\n    { \"id\": \"e1\", \"fromBlockId\": \"t1\", \"toBlockId\": \"f1\" },\n    { \"id\": \"e2\", \"fromBlockId\": \"f1\", \"toBlockId\": \"a1\", \"mode\": \"FOR_EACH\" }\n  ]\n}\n```\n\n**Validation.** At least one `TRIGGER` block; every edge must reference blocks in the set; self-loops and cycles are rejected (the graph must be a DAG). Block/edge ids are client-chosen and must be unique within the automation.\n\n**Scope:** `automations:write`  \n**Min role:** `CONTRIBUTOR` or higher  \n**Endpoint:** `POST /api/automations`","operationId":"automations.automations","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"organizationId":{"type":"string","minLength":1},"name":{"type":"string","minLength":1,"maxLength":200},"description":{"type":"string","maxLength":2000},"blocks":{"default":[],"maxItems":100,"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1,"description":"Client-chosen id, unique within the automation. Edges reference blocks by this id, and downstream blocks read this block's output via {{blocks.<id>.…}} bindings."},"kind":{"type":"string","enum":["TRIGGER","FILTER","ACTION","CUSTOM"],"description":"TRIGGER starts the flow when its event fires (every automation needs at least one); FILTER queries org data and outputs a shaped list/value; ACTION invokes a tool; CUSTOM is reserved and not executable in v1."},"ref":{"description":"What the block invokes. TRIGGER: an event type from the catalog, e.g. \"invoice.paid\" or \"schedule.daily\" (GET /api/automations/actions lists them). ACTION: an MCP tool name, e.g. \"invoices.send\", or engine-native \"webhook.post\" / \"email.send\". FILTER: omit — the query lives in config.spec.","anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"config":{"description":"Kind-specific configuration. ACTION: { input: { … } } — the arguments for the tool named by ref, matching that tool's inputSchema from the catalog; values may embed {{…}} bindings ({{trigger.*}}, {{blocks.<id>.*}}, {{item.*}} under a FOR_EACH edge, {{context.now}}, {{context.today}}, {{context.orgId}}) — a whole-string binding like \"{{trigger.total}}\" keeps the value's native type, inline bindings interpolate into the string. FILTER: { spec: { root, follows?, predicates?, aggregateBy?, extract, shape? } } over the served filter catalog. TRIGGER: ignored.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"position":{"description":"Editor canvas hint ({ x, y }). Ignored by the engine.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["id","kind"],"additionalProperties":false}},"edges":{"default":[],"maxItems":300,"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1,"description":"Client-chosen id, unique within the automation."},"fromBlockId":{"type":"string","minLength":1,"description":"Id of the source block. The graph must be a DAG — self-loops and cycles are rejected."},"toBlockId":{"type":"string","minLength":1,"description":"Id of the target block. The target runs only after the source step succeeds and the cond (if any) passes."},"cond":{"description":"Optional guard — null/omitted means the edge is always followed. Leaf: { left, op, right? } with op one of eq | ne | gt | gte | lt | lte | in | nin | contains | exists | empty; compose with { all: […] }, { any: […] }, { not: … }. Operands may be literals or {{…}} bindings; comparisons are type-light (100 equals \"100\").","anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"mode":{"description":"ONCE (default) passes the source output downstream as-is; FOR_EACH fans a list-valued source output out, running the target once per element (exposed as {{item.*}}) — a non-list source falls back to a single run.","type":"string","enum":["ONCE","FOR_EACH"]},"order":{"description":"Display ordering only — execution order is topological.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","fromBlockId","toBlockId"],"additionalProperties":false}}},"required":["organizationId","name","blocks","edges"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"ownerUserId":{"type":"string","description":"The run-as identity: when the automation fires, actions execute under this user's current org permissions."},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["DRAFT","ENABLED","PAUSED","PAUSED_NO_ACCESS"],"description":"DRAFT = never armed; ENABLED = armed (fires on its trigger; the free tier allows 5 enabled per org); PAUSED = manually disarmed; PAUSED_NO_ACCESS = auto-paused because the owner lost the required org access."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"blocks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Client-chosen id, unique within the automation. Edges reference blocks by this id, and downstream blocks read this block's output via {{blocks.<id>.…}} bindings."},"kind":{"type":"string","enum":["TRIGGER","FILTER","ACTION","CUSTOM"],"description":"TRIGGER starts the flow when its event fires (every automation needs at least one); FILTER queries org data and outputs a shaped list/value; ACTION invokes a tool; CUSTOM is reserved and not executable in v1."},"ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What the block invokes. TRIGGER: an event type from the catalog, e.g. \"invoice.paid\" or \"schedule.daily\" (GET /api/automations/actions lists them). ACTION: an MCP tool name, e.g. \"invoices.send\", or engine-native \"webhook.post\" / \"email.send\". FILTER: omit — the query lives in config.spec."},"config":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Kind-specific configuration. ACTION: { input: { … } } — the arguments for the tool named by ref, matching that tool's inputSchema from the catalog; values may embed {{…}} bindings ({{trigger.*}}, {{blocks.<id>.*}}, {{item.*}} under a FOR_EACH edge, {{context.now}}, {{context.today}}, {{context.orgId}}) — a whole-string binding like \"{{trigger.total}}\" keeps the value's native type, inline bindings interpolate into the string. FILTER: { spec: { root, follows?, predicates?, aggregateBy?, extract, shape? } } over the served filter catalog. TRIGGER: ignored."},"position":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Editor canvas hint ({ x, y }). Ignored by the engine."}},"required":["id","kind","ref","config","position"],"additionalProperties":false}},"edges":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Client-chosen id, unique within the automation."},"fromBlockId":{"type":"string","description":"Id of the source block. The graph must be a DAG — self-loops and cycles are rejected."},"toBlockId":{"type":"string","description":"Id of the target block. The target runs only after the source step succeeds and the cond (if any) passes."},"cond":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}],"description":"Optional guard — null/omitted means the edge is always followed. Leaf: { left, op, right? } with op one of eq | ne | gt | gte | lt | lte | in | nin | contains | exists | empty; compose with { all: […] }, { any: […] }, { not: … }. Operands may be literals or {{…}} bindings; comparisons are type-light (100 equals \"100\")."},"mode":{"type":"string","enum":["ONCE","FOR_EACH"],"description":"ONCE (default) passes the source output downstream as-is; FOR_EACH fans a list-valued source output out, running the target once per element (exposed as {{item.*}}) — a non-list source falls back to a single run."},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Display ordering only — execution order is topological."}},"required":["id","fromBlockId","toBlockId","cond","mode","order"],"additionalProperties":false}}},"required":["id","organizationId","ownerUserId","name","description","status","createdAt","updatedAt"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"ownerUserId":{"type":"string","description":"The run-as identity: when the automation fires, actions execute under this user's current org permissions."},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["DRAFT","ENABLED","PAUSED","PAUSED_NO_ACCESS"],"description":"DRAFT = never armed; ENABLED = armed (fires on its trigger; the free tier allows 5 enabled per org); PAUSED = manually disarmed; PAUSED_NO_ACCESS = auto-paused because the owner lost the required org access."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"blocks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Client-chosen id, unique within the automation. Edges reference blocks by this id, and downstream blocks read this block's output via {{blocks.<id>.…}} bindings."},"kind":{"type":"string","enum":["TRIGGER","FILTER","ACTION","CUSTOM"],"description":"TRIGGER starts the flow when its event fires (every automation needs at least one); FILTER queries org data and outputs a shaped list/value; ACTION invokes a tool; CUSTOM is reserved and not executable in v1."},"ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What the block invokes. TRIGGER: an event type from the catalog, e.g. \"invoice.paid\" or \"schedule.daily\" (GET /api/automations/actions lists them). ACTION: an MCP tool name, e.g. \"invoices.send\", or engine-native \"webhook.post\" / \"email.send\". FILTER: omit — the query lives in config.spec."},"config":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Kind-specific configuration. ACTION: { input: { … } } — the arguments for the tool named by ref, matching that tool's inputSchema from the catalog; values may embed {{…}} bindings ({{trigger.*}}, {{blocks.<id>.*}}, {{item.*}} under a FOR_EACH edge, {{context.now}}, {{context.today}}, {{context.orgId}}) — a whole-string binding like \"{{trigger.total}}\" keeps the value's native type, inline bindings interpolate into the string. FILTER: { spec: { root, follows?, predicates?, aggregateBy?, extract, shape? } } over the served filter catalog. TRIGGER: ignored."},"position":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Editor canvas hint ({ x, y }). Ignored by the engine."}},"required":["id","kind","ref","config","position"],"additionalProperties":false}},"edges":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Client-chosen id, unique within the automation."},"fromBlockId":{"type":"string","description":"Id of the source block. The graph must be a DAG — self-loops and cycles are rejected."},"toBlockId":{"type":"string","description":"Id of the target block. The target runs only after the source step succeeds and the cond (if any) passes."},"cond":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}],"description":"Optional guard — null/omitted means the edge is always followed. Leaf: { left, op, right? } with op one of eq | ne | gt | gte | lt | lte | in | nin | contains | exists | empty; compose with { all: […] }, { any: […] }, { not: … }. Operands may be literals or {{…}} bindings; comparisons are type-light (100 equals \"100\")."},"mode":{"type":"string","enum":["ONCE","FOR_EACH"],"description":"ONCE (default) passes the source output downstream as-is; FOR_EACH fans a list-valued source output out, running the target once per element (exposed as {{item.*}}) — a non-list source falls back to a single run."},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Display ordering only — execution order is topological."}},"required":["id","fromBlockId","toBlockId","cond","mode","order"],"additionalProperties":false}}},"required":["id","organizationId","ownerUserId","name","description","status","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["automations:write"]}],"x-guliel-feature":"automations","x-guliel-verb":"write","x-guliel-required-role":"CONTRIBUTOR","x-guliel-scope":"automations:write"}},"/api/automations/{id}":{"get":{"tags":["automations"],"summary":"Get an automation (with its graph)","description":"Fetches a single automation by id. Returns 404 if the automation isn't in the caller's accessible organizations.\n\n**Scope:** `automations:read`  \n**Endpoint:** `GET /api/automations/{id}`","operationId":"automations.get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"ownerUserId":{"type":"string","description":"The run-as identity: when the automation fires, actions execute under this user's current org permissions."},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["DRAFT","ENABLED","PAUSED","PAUSED_NO_ACCESS"],"description":"DRAFT = never armed; ENABLED = armed (fires on its trigger; the free tier allows 5 enabled per org); PAUSED = manually disarmed; PAUSED_NO_ACCESS = auto-paused because the owner lost the required org access."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"blocks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Client-chosen id, unique within the automation. Edges reference blocks by this id, and downstream blocks read this block's output via {{blocks.<id>.…}} bindings."},"kind":{"type":"string","enum":["TRIGGER","FILTER","ACTION","CUSTOM"],"description":"TRIGGER starts the flow when its event fires (every automation needs at least one); FILTER queries org data and outputs a shaped list/value; ACTION invokes a tool; CUSTOM is reserved and not executable in v1."},"ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What the block invokes. TRIGGER: an event type from the catalog, e.g. \"invoice.paid\" or \"schedule.daily\" (GET /api/automations/actions lists them). ACTION: an MCP tool name, e.g. \"invoices.send\", or engine-native \"webhook.post\" / \"email.send\". FILTER: omit — the query lives in config.spec."},"config":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Kind-specific configuration. ACTION: { input: { … } } — the arguments for the tool named by ref, matching that tool's inputSchema from the catalog; values may embed {{…}} bindings ({{trigger.*}}, {{blocks.<id>.*}}, {{item.*}} under a FOR_EACH edge, {{context.now}}, {{context.today}}, {{context.orgId}}) — a whole-string binding like \"{{trigger.total}}\" keeps the value's native type, inline bindings interpolate into the string. FILTER: { spec: { root, follows?, predicates?, aggregateBy?, extract, shape? } } over the served filter catalog. TRIGGER: ignored."},"position":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Editor canvas hint ({ x, y }). Ignored by the engine."}},"required":["id","kind","ref","config","position"],"additionalProperties":false}},"edges":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Client-chosen id, unique within the automation."},"fromBlockId":{"type":"string","description":"Id of the source block. The graph must be a DAG — self-loops and cycles are rejected."},"toBlockId":{"type":"string","description":"Id of the target block. The target runs only after the source step succeeds and the cond (if any) passes."},"cond":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}],"description":"Optional guard — null/omitted means the edge is always followed. Leaf: { left, op, right? } with op one of eq | ne | gt | gte | lt | lte | in | nin | contains | exists | empty; compose with { all: […] }, { any: […] }, { not: … }. Operands may be literals or {{…}} bindings; comparisons are type-light (100 equals \"100\")."},"mode":{"type":"string","enum":["ONCE","FOR_EACH"],"description":"ONCE (default) passes the source output downstream as-is; FOR_EACH fans a list-valued source output out, running the target once per element (exposed as {{item.*}}) — a non-list source falls back to a single run."},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Display ordering only — execution order is topological."}},"required":["id","fromBlockId","toBlockId","cond","mode","order"],"additionalProperties":false}}},"required":["id","organizationId","ownerUserId","name","description","status","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["automations:read"]}],"x-guliel-feature":"automations","x-guliel-verb":"read","x-guliel-scope":"automations:read"},"patch":{"tags":["automations"],"summary":"Update an automation (rename / edit its graph)","description":"Updates an existing automation. Only the fields present in the request body are changed; omitted fields stay as-is.\n\n**Scope:** `automations:write`  \n**Endpoint:** `PATCH /api/automations/{id}`","operationId":"automations.update","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","minLength":1,"maxLength":200},"description":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]},"blocks":{"maxItems":100,"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1,"description":"Client-chosen id, unique within the automation. Edges reference blocks by this id, and downstream blocks read this block's output via {{blocks.<id>.…}} bindings."},"kind":{"type":"string","enum":["TRIGGER","FILTER","ACTION","CUSTOM"],"description":"TRIGGER starts the flow when its event fires (every automation needs at least one); FILTER queries org data and outputs a shaped list/value; ACTION invokes a tool; CUSTOM is reserved and not executable in v1."},"ref":{"description":"What the block invokes. TRIGGER: an event type from the catalog, e.g. \"invoice.paid\" or \"schedule.daily\" (GET /api/automations/actions lists them). ACTION: an MCP tool name, e.g. \"invoices.send\", or engine-native \"webhook.post\" / \"email.send\". FILTER: omit — the query lives in config.spec.","anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"config":{"description":"Kind-specific configuration. ACTION: { input: { … } } — the arguments for the tool named by ref, matching that tool's inputSchema from the catalog; values may embed {{…}} bindings ({{trigger.*}}, {{blocks.<id>.*}}, {{item.*}} under a FOR_EACH edge, {{context.now}}, {{context.today}}, {{context.orgId}}) — a whole-string binding like \"{{trigger.total}}\" keeps the value's native type, inline bindings interpolate into the string. FILTER: { spec: { root, follows?, predicates?, aggregateBy?, extract, shape? } } over the served filter catalog. TRIGGER: ignored.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"position":{"description":"Editor canvas hint ({ x, y }). Ignored by the engine.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["id","kind"],"additionalProperties":false}},"edges":{"maxItems":300,"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1,"description":"Client-chosen id, unique within the automation."},"fromBlockId":{"type":"string","minLength":1,"description":"Id of the source block. The graph must be a DAG — self-loops and cycles are rejected."},"toBlockId":{"type":"string","minLength":1,"description":"Id of the target block. The target runs only after the source step succeeds and the cond (if any) passes."},"cond":{"description":"Optional guard — null/omitted means the edge is always followed. Leaf: { left, op, right? } with op one of eq | ne | gt | gte | lt | lte | in | nin | contains | exists | empty; compose with { all: […] }, { any: […] }, { not: … }. Operands may be literals or {{…}} bindings; comparisons are type-light (100 equals \"100\").","anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"mode":{"description":"ONCE (default) passes the source output downstream as-is; FOR_EACH fans a list-valued source output out, running the target once per element (exposed as {{item.*}}) — a non-list source falls back to a single run.","type":"string","enum":["ONCE","FOR_EACH"]},"order":{"description":"Display ordering only — execution order is topological.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","fromBlockId","toBlockId"],"additionalProperties":false}}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"ownerUserId":{"type":"string","description":"The run-as identity: when the automation fires, actions execute under this user's current org permissions."},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["DRAFT","ENABLED","PAUSED","PAUSED_NO_ACCESS"],"description":"DRAFT = never armed; ENABLED = armed (fires on its trigger; the free tier allows 5 enabled per org); PAUSED = manually disarmed; PAUSED_NO_ACCESS = auto-paused because the owner lost the required org access."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"blocks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Client-chosen id, unique within the automation. Edges reference blocks by this id, and downstream blocks read this block's output via {{blocks.<id>.…}} bindings."},"kind":{"type":"string","enum":["TRIGGER","FILTER","ACTION","CUSTOM"],"description":"TRIGGER starts the flow when its event fires (every automation needs at least one); FILTER queries org data and outputs a shaped list/value; ACTION invokes a tool; CUSTOM is reserved and not executable in v1."},"ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What the block invokes. TRIGGER: an event type from the catalog, e.g. \"invoice.paid\" or \"schedule.daily\" (GET /api/automations/actions lists them). ACTION: an MCP tool name, e.g. \"invoices.send\", or engine-native \"webhook.post\" / \"email.send\". FILTER: omit — the query lives in config.spec."},"config":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Kind-specific configuration. ACTION: { input: { … } } — the arguments for the tool named by ref, matching that tool's inputSchema from the catalog; values may embed {{…}} bindings ({{trigger.*}}, {{blocks.<id>.*}}, {{item.*}} under a FOR_EACH edge, {{context.now}}, {{context.today}}, {{context.orgId}}) — a whole-string binding like \"{{trigger.total}}\" keeps the value's native type, inline bindings interpolate into the string. FILTER: { spec: { root, follows?, predicates?, aggregateBy?, extract, shape? } } over the served filter catalog. TRIGGER: ignored."},"position":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Editor canvas hint ({ x, y }). Ignored by the engine."}},"required":["id","kind","ref","config","position"],"additionalProperties":false}},"edges":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Client-chosen id, unique within the automation."},"fromBlockId":{"type":"string","description":"Id of the source block. The graph must be a DAG — self-loops and cycles are rejected."},"toBlockId":{"type":"string","description":"Id of the target block. The target runs only after the source step succeeds and the cond (if any) passes."},"cond":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}],"description":"Optional guard — null/omitted means the edge is always followed. Leaf: { left, op, right? } with op one of eq | ne | gt | gte | lt | lte | in | nin | contains | exists | empty; compose with { all: […] }, { any: […] }, { not: … }. Operands may be literals or {{…}} bindings; comparisons are type-light (100 equals \"100\")."},"mode":{"type":"string","enum":["ONCE","FOR_EACH"],"description":"ONCE (default) passes the source output downstream as-is; FOR_EACH fans a list-valued source output out, running the target once per element (exposed as {{item.*}}) — a non-list source falls back to a single run."},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Display ordering only — execution order is topological."}},"required":["id","fromBlockId","toBlockId","cond","mode","order"],"additionalProperties":false}}},"required":["id","organizationId","ownerUserId","name","description","status","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["automations:write"]}],"x-guliel-feature":"automations","x-guliel-verb":"write","x-guliel-scope":"automations:write"},"delete":{"tags":["automations"],"summary":"Delete an automation","description":"Deletes the automation. Some endpoints hard-delete the row, others soft-revoke (set `revokedAt`). Check the response shape.\n\n**Scope:** `automations:write`  \n**Endpoint:** `DELETE /api/automations/{id}`","operationId":"automations.delete","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true}},"required":["success"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["automations:write"]}],"x-guliel-feature":"automations","x-guliel-verb":"write","x-guliel-scope":"automations:write"}},"/api/automations/{id}/disable":{"post":{"tags":["automations"],"summary":"Disable (disarm) an automation","description":"Creates a new `disable` attached to the given automation.\n\n**Scope:** `automations:write`  \n**Endpoint:** `POST /api/automations/{id}/disable`","operationId":"automations.disable","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"ownerUserId":{"type":"string","description":"The run-as identity: when the automation fires, actions execute under this user's current org permissions."},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["DRAFT","ENABLED","PAUSED","PAUSED_NO_ACCESS"],"description":"DRAFT = never armed; ENABLED = armed (fires on its trigger; the free tier allows 5 enabled per org); PAUSED = manually disarmed; PAUSED_NO_ACCESS = auto-paused because the owner lost the required org access."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"blocks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Client-chosen id, unique within the automation. Edges reference blocks by this id, and downstream blocks read this block's output via {{blocks.<id>.…}} bindings."},"kind":{"type":"string","enum":["TRIGGER","FILTER","ACTION","CUSTOM"],"description":"TRIGGER starts the flow when its event fires (every automation needs at least one); FILTER queries org data and outputs a shaped list/value; ACTION invokes a tool; CUSTOM is reserved and not executable in v1."},"ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What the block invokes. TRIGGER: an event type from the catalog, e.g. \"invoice.paid\" or \"schedule.daily\" (GET /api/automations/actions lists them). ACTION: an MCP tool name, e.g. \"invoices.send\", or engine-native \"webhook.post\" / \"email.send\". FILTER: omit — the query lives in config.spec."},"config":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Kind-specific configuration. ACTION: { input: { … } } — the arguments for the tool named by ref, matching that tool's inputSchema from the catalog; values may embed {{…}} bindings ({{trigger.*}}, {{blocks.<id>.*}}, {{item.*}} under a FOR_EACH edge, {{context.now}}, {{context.today}}, {{context.orgId}}) — a whole-string binding like \"{{trigger.total}}\" keeps the value's native type, inline bindings interpolate into the string. FILTER: { spec: { root, follows?, predicates?, aggregateBy?, extract, shape? } } over the served filter catalog. TRIGGER: ignored."},"position":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Editor canvas hint ({ x, y }). Ignored by the engine."}},"required":["id","kind","ref","config","position"],"additionalProperties":false}},"edges":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Client-chosen id, unique within the automation."},"fromBlockId":{"type":"string","description":"Id of the source block. The graph must be a DAG — self-loops and cycles are rejected."},"toBlockId":{"type":"string","description":"Id of the target block. The target runs only after the source step succeeds and the cond (if any) passes."},"cond":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}],"description":"Optional guard — null/omitted means the edge is always followed. Leaf: { left, op, right? } with op one of eq | ne | gt | gte | lt | lte | in | nin | contains | exists | empty; compose with { all: […] }, { any: […] }, { not: … }. Operands may be literals or {{…}} bindings; comparisons are type-light (100 equals \"100\")."},"mode":{"type":"string","enum":["ONCE","FOR_EACH"],"description":"ONCE (default) passes the source output downstream as-is; FOR_EACH fans a list-valued source output out, running the target once per element (exposed as {{item.*}}) — a non-list source falls back to a single run."},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Display ordering only — execution order is topological."}},"required":["id","fromBlockId","toBlockId","cond","mode","order"],"additionalProperties":false}}},"required":["id","organizationId","ownerUserId","name","description","status","createdAt","updatedAt"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"ownerUserId":{"type":"string","description":"The run-as identity: when the automation fires, actions execute under this user's current org permissions."},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["DRAFT","ENABLED","PAUSED","PAUSED_NO_ACCESS"],"description":"DRAFT = never armed; ENABLED = armed (fires on its trigger; the free tier allows 5 enabled per org); PAUSED = manually disarmed; PAUSED_NO_ACCESS = auto-paused because the owner lost the required org access."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"blocks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Client-chosen id, unique within the automation. Edges reference blocks by this id, and downstream blocks read this block's output via {{blocks.<id>.…}} bindings."},"kind":{"type":"string","enum":["TRIGGER","FILTER","ACTION","CUSTOM"],"description":"TRIGGER starts the flow when its event fires (every automation needs at least one); FILTER queries org data and outputs a shaped list/value; ACTION invokes a tool; CUSTOM is reserved and not executable in v1."},"ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What the block invokes. TRIGGER: an event type from the catalog, e.g. \"invoice.paid\" or \"schedule.daily\" (GET /api/automations/actions lists them). ACTION: an MCP tool name, e.g. \"invoices.send\", or engine-native \"webhook.post\" / \"email.send\". FILTER: omit — the query lives in config.spec."},"config":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Kind-specific configuration. ACTION: { input: { … } } — the arguments for the tool named by ref, matching that tool's inputSchema from the catalog; values may embed {{…}} bindings ({{trigger.*}}, {{blocks.<id>.*}}, {{item.*}} under a FOR_EACH edge, {{context.now}}, {{context.today}}, {{context.orgId}}) — a whole-string binding like \"{{trigger.total}}\" keeps the value's native type, inline bindings interpolate into the string. FILTER: { spec: { root, follows?, predicates?, aggregateBy?, extract, shape? } } over the served filter catalog. TRIGGER: ignored."},"position":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Editor canvas hint ({ x, y }). Ignored by the engine."}},"required":["id","kind","ref","config","position"],"additionalProperties":false}},"edges":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Client-chosen id, unique within the automation."},"fromBlockId":{"type":"string","description":"Id of the source block. The graph must be a DAG — self-loops and cycles are rejected."},"toBlockId":{"type":"string","description":"Id of the target block. The target runs only after the source step succeeds and the cond (if any) passes."},"cond":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}],"description":"Optional guard — null/omitted means the edge is always followed. Leaf: { left, op, right? } with op one of eq | ne | gt | gte | lt | lte | in | nin | contains | exists | empty; compose with { all: […] }, { any: […] }, { not: … }. Operands may be literals or {{…}} bindings; comparisons are type-light (100 equals \"100\")."},"mode":{"type":"string","enum":["ONCE","FOR_EACH"],"description":"ONCE (default) passes the source output downstream as-is; FOR_EACH fans a list-valued source output out, running the target once per element (exposed as {{item.*}}) — a non-list source falls back to a single run."},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Display ordering only — execution order is topological."}},"required":["id","fromBlockId","toBlockId","cond","mode","order"],"additionalProperties":false}}},"required":["id","organizationId","ownerUserId","name","description","status","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["automations:write"]}],"x-guliel-feature":"automations","x-guliel-verb":"write","x-guliel-scope":"automations:write"}},"/api/automations/{id}/enable":{"post":{"tags":["automations"],"summary":"Enable (arm) an automation","description":"Creates a new `enable` attached to the given automation.\n\n**Scope:** `automations:write`  \n**Endpoint:** `POST /api/automations/{id}/enable`","operationId":"automations.enable","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"ownerUserId":{"type":"string","description":"The run-as identity: when the automation fires, actions execute under this user's current org permissions."},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["DRAFT","ENABLED","PAUSED","PAUSED_NO_ACCESS"],"description":"DRAFT = never armed; ENABLED = armed (fires on its trigger; the free tier allows 5 enabled per org); PAUSED = manually disarmed; PAUSED_NO_ACCESS = auto-paused because the owner lost the required org access."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"blocks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Client-chosen id, unique within the automation. Edges reference blocks by this id, and downstream blocks read this block's output via {{blocks.<id>.…}} bindings."},"kind":{"type":"string","enum":["TRIGGER","FILTER","ACTION","CUSTOM"],"description":"TRIGGER starts the flow when its event fires (every automation needs at least one); FILTER queries org data and outputs a shaped list/value; ACTION invokes a tool; CUSTOM is reserved and not executable in v1."},"ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What the block invokes. TRIGGER: an event type from the catalog, e.g. \"invoice.paid\" or \"schedule.daily\" (GET /api/automations/actions lists them). ACTION: an MCP tool name, e.g. \"invoices.send\", or engine-native \"webhook.post\" / \"email.send\". FILTER: omit — the query lives in config.spec."},"config":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Kind-specific configuration. ACTION: { input: { … } } — the arguments for the tool named by ref, matching that tool's inputSchema from the catalog; values may embed {{…}} bindings ({{trigger.*}}, {{blocks.<id>.*}}, {{item.*}} under a FOR_EACH edge, {{context.now}}, {{context.today}}, {{context.orgId}}) — a whole-string binding like \"{{trigger.total}}\" keeps the value's native type, inline bindings interpolate into the string. FILTER: { spec: { root, follows?, predicates?, aggregateBy?, extract, shape? } } over the served filter catalog. TRIGGER: ignored."},"position":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Editor canvas hint ({ x, y }). Ignored by the engine."}},"required":["id","kind","ref","config","position"],"additionalProperties":false}},"edges":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Client-chosen id, unique within the automation."},"fromBlockId":{"type":"string","description":"Id of the source block. The graph must be a DAG — self-loops and cycles are rejected."},"toBlockId":{"type":"string","description":"Id of the target block. The target runs only after the source step succeeds and the cond (if any) passes."},"cond":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}],"description":"Optional guard — null/omitted means the edge is always followed. Leaf: { left, op, right? } with op one of eq | ne | gt | gte | lt | lte | in | nin | contains | exists | empty; compose with { all: […] }, { any: […] }, { not: … }. Operands may be literals or {{…}} bindings; comparisons are type-light (100 equals \"100\")."},"mode":{"type":"string","enum":["ONCE","FOR_EACH"],"description":"ONCE (default) passes the source output downstream as-is; FOR_EACH fans a list-valued source output out, running the target once per element (exposed as {{item.*}}) — a non-list source falls back to a single run."},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Display ordering only — execution order is topological."}},"required":["id","fromBlockId","toBlockId","cond","mode","order"],"additionalProperties":false}}},"required":["id","organizationId","ownerUserId","name","description","status","createdAt","updatedAt"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"ownerUserId":{"type":"string","description":"The run-as identity: when the automation fires, actions execute under this user's current org permissions."},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["DRAFT","ENABLED","PAUSED","PAUSED_NO_ACCESS"],"description":"DRAFT = never armed; ENABLED = armed (fires on its trigger; the free tier allows 5 enabled per org); PAUSED = manually disarmed; PAUSED_NO_ACCESS = auto-paused because the owner lost the required org access."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"blocks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Client-chosen id, unique within the automation. Edges reference blocks by this id, and downstream blocks read this block's output via {{blocks.<id>.…}} bindings."},"kind":{"type":"string","enum":["TRIGGER","FILTER","ACTION","CUSTOM"],"description":"TRIGGER starts the flow when its event fires (every automation needs at least one); FILTER queries org data and outputs a shaped list/value; ACTION invokes a tool; CUSTOM is reserved and not executable in v1."},"ref":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"What the block invokes. TRIGGER: an event type from the catalog, e.g. \"invoice.paid\" or \"schedule.daily\" (GET /api/automations/actions lists them). ACTION: an MCP tool name, e.g. \"invoices.send\", or engine-native \"webhook.post\" / \"email.send\". FILTER: omit — the query lives in config.spec."},"config":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Kind-specific configuration. ACTION: { input: { … } } — the arguments for the tool named by ref, matching that tool's inputSchema from the catalog; values may embed {{…}} bindings ({{trigger.*}}, {{blocks.<id>.*}}, {{item.*}} under a FOR_EACH edge, {{context.now}}, {{context.today}}, {{context.orgId}}) — a whole-string binding like \"{{trigger.total}}\" keeps the value's native type, inline bindings interpolate into the string. FILTER: { spec: { root, follows?, predicates?, aggregateBy?, extract, shape? } } over the served filter catalog. TRIGGER: ignored."},"position":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Editor canvas hint ({ x, y }). Ignored by the engine."}},"required":["id","kind","ref","config","position"],"additionalProperties":false}},"edges":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Client-chosen id, unique within the automation."},"fromBlockId":{"type":"string","description":"Id of the source block. The graph must be a DAG — self-loops and cycles are rejected."},"toBlockId":{"type":"string","description":"Id of the target block. The target runs only after the source step succeeds and the cond (if any) passes."},"cond":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}],"description":"Optional guard — null/omitted means the edge is always followed. Leaf: { left, op, right? } with op one of eq | ne | gt | gte | lt | lte | in | nin | contains | exists | empty; compose with { all: […] }, { any: […] }, { not: … }. Operands may be literals or {{…}} bindings; comparisons are type-light (100 equals \"100\")."},"mode":{"type":"string","enum":["ONCE","FOR_EACH"],"description":"ONCE (default) passes the source output downstream as-is; FOR_EACH fans a list-valued source output out, running the target once per element (exposed as {{item.*}}) — a non-list source falls back to a single run."},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Display ordering only — execution order is topological."}},"required":["id","fromBlockId","toBlockId","cond","mode","order"],"additionalProperties":false}}},"required":["id","organizationId","ownerUserId","name","description","status","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["automations:write"]}],"x-guliel-feature":"automations","x-guliel-verb":"write","x-guliel-scope":"automations:write"}},"/api/automations/{id}/runs":{"get":{"tags":["automations"],"summary":"List an automation's runs (history)","description":"Returns every `runs` row associated with the given automation.\n\n**Scope:** `automations:read`  \n**Endpoint:** `GET /api/automations/{id}/runs`","operationId":"automations.runs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."},{"name":"page","in":"query","required":true,"schema":{"default":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"name":"limit","in":"query","required":true,"schema":{"default":25,"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"runs":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"automationId":{"type":"string"},"organizationId":{"type":"string"},"triggerEventId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The outbox event that fired this run; null for a manual test run."},"input":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"The trigger payload the run was seeded with — what {{trigger.*}} resolved against."},"status":{"type":"string","enum":["RUNNING","SUCCEEDED","FAILED","CANCELLED"],"description":"FAILED pauses at the first failed step; a FAILED run can be resumed via replay."},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedAt":{"type":"string"},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"steps":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"blockId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The block this step executed; null if that block was later edited out of the graph."},"status":{"type":"string","enum":["PENDING","RUNNING","SUCCEEDED","FAILED","SKIPPED"],"description":"SKIPPED = no incoming edge had a succeeded source with a passing cond."},"input":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"The block's resolved input (bindings already substituted)."},"output":{"anyOf":[{},{"type":"null"}],"description":"The block's output — what downstream {{blocks.<id>.…}} bindings read."},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"attempt":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"1-based; transient action failures are retried."},"latencyMs":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"startedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","blockId","status","input","output","error","attempt","latencyMs","startedAt","finishedAt"],"additionalProperties":false}}},"required":["id","automationId","organizationId","triggerEventId","input","status","error","startedAt","finishedAt"],"additionalProperties":false}},"pagination":{"type":"object","properties":{"page":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"totalPages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["page","limit","total","totalPages"],"additionalProperties":false}},"required":["runs","pagination"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["automations:read"]}],"x-guliel-feature":"automations","x-guliel-verb":"read","x-guliel-scope":"automations:read"}},"/api/automations/{id}/runs/{runId}":{"get":{"tags":["automations"],"summary":"Get a run with its step timeline","description":"Returns every `runs` row associated with the given automation.\n\n**Scope:** `automations:read`  \n**Endpoint:** `GET /api/automations/{id}/runs/{runId}`","operationId":"automations.get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."},{"name":"runId","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `runId` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"automationId":{"type":"string"},"organizationId":{"type":"string"},"triggerEventId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The outbox event that fired this run; null for a manual test run."},"input":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"The trigger payload the run was seeded with — what {{trigger.*}} resolved against."},"status":{"type":"string","enum":["RUNNING","SUCCEEDED","FAILED","CANCELLED"],"description":"FAILED pauses at the first failed step; a FAILED run can be resumed via replay."},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedAt":{"type":"string"},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"steps":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"blockId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The block this step executed; null if that block was later edited out of the graph."},"status":{"type":"string","enum":["PENDING","RUNNING","SUCCEEDED","FAILED","SKIPPED"],"description":"SKIPPED = no incoming edge had a succeeded source with a passing cond."},"input":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"The block's resolved input (bindings already substituted)."},"output":{"anyOf":[{},{"type":"null"}],"description":"The block's output — what downstream {{blocks.<id>.…}} bindings read."},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"attempt":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"1-based; transient action failures are retried."},"latencyMs":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"startedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","blockId","status","input","output","error","attempt","latencyMs","startedAt","finishedAt"],"additionalProperties":false}}},"required":["id","automationId","organizationId","triggerEventId","input","status","error","startedAt","finishedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["automations:read"]}],"x-guliel-feature":"automations","x-guliel-verb":"read","x-guliel-scope":"automations:read"}},"/api/automations/{id}/runs/{runId}/replay":{"post":{"tags":["automations"],"summary":"Replay a failed run (resume from the failed step)","description":"Creates a new `runs/replay` attached to the given automation.\n\n**Scope:** `automations:write`  \n**Min role:** `CONTRIBUTOR` or higher  \n**Endpoint:** `POST /api/automations/{id}/runs/{runId}/replay`","operationId":"automations.replay","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."},{"name":"runId","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `runId` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"runId":{"type":"string"}},"required":["id","runId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"automationId":{"type":"string"},"organizationId":{"type":"string"},"triggerEventId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The outbox event that fired this run; null for a manual test run."},"input":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"The trigger payload the run was seeded with — what {{trigger.*}} resolved against."},"status":{"type":"string","enum":["RUNNING","SUCCEEDED","FAILED","CANCELLED"],"description":"FAILED pauses at the first failed step; a FAILED run can be resumed via replay."},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedAt":{"type":"string"},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"steps":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"blockId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The block this step executed; null if that block was later edited out of the graph."},"status":{"type":"string","enum":["PENDING","RUNNING","SUCCEEDED","FAILED","SKIPPED"],"description":"SKIPPED = no incoming edge had a succeeded source with a passing cond."},"input":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"The block's resolved input (bindings already substituted)."},"output":{"anyOf":[{},{"type":"null"}],"description":"The block's output — what downstream {{blocks.<id>.…}} bindings read."},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"attempt":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"1-based; transient action failures are retried."},"latencyMs":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"startedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","blockId","status","input","output","error","attempt","latencyMs","startedAt","finishedAt"],"additionalProperties":false}}},"required":["id","automationId","organizationId","triggerEventId","input","status","error","startedAt","finishedAt"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"automationId":{"type":"string"},"organizationId":{"type":"string"},"triggerEventId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The outbox event that fired this run; null for a manual test run."},"input":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"The trigger payload the run was seeded with — what {{trigger.*}} resolved against."},"status":{"type":"string","enum":["RUNNING","SUCCEEDED","FAILED","CANCELLED"],"description":"FAILED pauses at the first failed step; a FAILED run can be resumed via replay."},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedAt":{"type":"string"},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"steps":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"blockId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The block this step executed; null if that block was later edited out of the graph."},"status":{"type":"string","enum":["PENDING","RUNNING","SUCCEEDED","FAILED","SKIPPED"],"description":"SKIPPED = no incoming edge had a succeeded source with a passing cond."},"input":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"The block's resolved input (bindings already substituted)."},"output":{"anyOf":[{},{"type":"null"}],"description":"The block's output — what downstream {{blocks.<id>.…}} bindings read."},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"attempt":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"1-based; transient action failures are retried."},"latencyMs":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"startedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","blockId","status","input","output","error","attempt","latencyMs","startedAt","finishedAt"],"additionalProperties":false}}},"required":["id","automationId","organizationId","triggerEventId","input","status","error","startedAt","finishedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["automations:write"]}],"x-guliel-feature":"automations","x-guliel-verb":"write","x-guliel-required-role":"CONTRIBUTOR","x-guliel-scope":"automations:write"}},"/api/automations/{id}/test":{"post":{"tags":["automations"],"summary":"Test-run an automation with a sample payload (owner or MANAGER)","description":"Creates a new `test` attached to the given automation.\n\nRuns the flow **inline in this request** (unlike a real fire, which goes through the event queue) and returns the run with its step timeline immediately. The run executes under the automation **owner's** permissions — real fire-time authorization — which is why only the owner or a `MANAGER` may call it. Actions really execute; there is no dry-run mode. Shape `payload` like the trigger's `payloadSchema` from `GET /api/automations/actions` so `{{trigger.*}}` bindings resolve.\n\n**Scope:** `automations:write`  \n**Min role:** `CONTRIBUTOR` or higher  \n**Endpoint:** `POST /api/automations/{id}/test`","operationId":"automations.test","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"payload":{"description":"Sample trigger payload — the value {{trigger.*}} bindings resolve against. Shape it like the trigger's payloadSchema from automations.catalog. Defaults to {}.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"automationId":{"type":"string"},"organizationId":{"type":"string"},"triggerEventId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The outbox event that fired this run; null for a manual test run."},"input":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"The trigger payload the run was seeded with — what {{trigger.*}} resolved against."},"status":{"type":"string","enum":["RUNNING","SUCCEEDED","FAILED","CANCELLED"],"description":"FAILED pauses at the first failed step; a FAILED run can be resumed via replay."},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedAt":{"type":"string"},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"steps":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"blockId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The block this step executed; null if that block was later edited out of the graph."},"status":{"type":"string","enum":["PENDING","RUNNING","SUCCEEDED","FAILED","SKIPPED"],"description":"SKIPPED = no incoming edge had a succeeded source with a passing cond."},"input":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"The block's resolved input (bindings already substituted)."},"output":{"anyOf":[{},{"type":"null"}],"description":"The block's output — what downstream {{blocks.<id>.…}} bindings read."},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"attempt":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"1-based; transient action failures are retried."},"latencyMs":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"startedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","blockId","status","input","output","error","attempt","latencyMs","startedAt","finishedAt"],"additionalProperties":false}}},"required":["id","automationId","organizationId","triggerEventId","input","status","error","startedAt","finishedAt"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"automationId":{"type":"string"},"organizationId":{"type":"string"},"triggerEventId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The outbox event that fired this run; null for a manual test run."},"input":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"The trigger payload the run was seeded with — what {{trigger.*}} resolved against."},"status":{"type":"string","enum":["RUNNING","SUCCEEDED","FAILED","CANCELLED"],"description":"FAILED pauses at the first failed step; a FAILED run can be resumed via replay."},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedAt":{"type":"string"},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"steps":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"blockId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The block this step executed; null if that block was later edited out of the graph."},"status":{"type":"string","enum":["PENDING","RUNNING","SUCCEEDED","FAILED","SKIPPED"],"description":"SKIPPED = no incoming edge had a succeeded source with a passing cond."},"input":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"The block's resolved input (bindings already substituted)."},"output":{"anyOf":[{},{"type":"null"}],"description":"The block's output — what downstream {{blocks.<id>.…}} bindings read."},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"attempt":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"1-based; transient action failures are retried."},"latencyMs":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"startedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","blockId","status","input","output","error","attempt","latencyMs","startedAt","finishedAt"],"additionalProperties":false}}},"required":["id","automationId","organizationId","triggerEventId","input","status","error","startedAt","finishedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["automations:write"]}],"x-guliel-feature":"automations","x-guliel-verb":"write","x-guliel-required-role":"CONTRIBUTOR","x-guliel-scope":"automations:write"}},"/api/automations/actions":{"get":{"tags":["automations"],"summary":"The block catalog for the automation editor (triggers + actions)","description":"Returns the `actions` data for the automations feature.\n\nThe discovery endpoint for authoring automations: consult it before `POST /api/automations`. `triggers` lists every event type a `TRIGGER` block may reference, with the payload schema `{{trigger.*}}` bindings resolve against. `actions` lists every tool an `ACTION` block may invoke — the platform's full MCP tool catalog plus the engine-native `webhook.post` and `email.send` — each carrying the input schema its `config.input` must satisfy and the output schema downstream bindings can read. `filterCatalog` lists the objects/fields/morphisms a `FILTER` block's `config.spec` may query.\n\n**Scope:** `automations:read`  \n**Endpoint:** `GET /api/automations/actions`","operationId":"automations.actions","parameters":[],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"triggers":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","description":"Event type — use as a TRIGGER block's ref (e.g. \"invoice.paid\", \"schedule.daily\")."},"label":{"type":"string"},"group":{"type":"string"},"payloadSchema":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}],"description":"JSON Schema for the trigger's event payload — the fields {{trigger.*}} bindings can reference."}},"required":["type","label","group","payloadSchema"],"additionalProperties":false},"description":"Event types usable as a TRIGGER block's ref."},"actions":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Tool name — use as an ACTION block's ref (e.g. \"invoices.send\", \"webhook.post\")."},"description":{"type":"string"},"feature":{"type":"string"},"verb":{"type":"string"},"kind":{"type":"string","enum":["system","engine"],"description":"system = an API route invoked as a tool; engine = built into the worker."},"inputSchema":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}],"description":"JSON Schema (draft-7) for the action's input — the shape an ACTION block's config.input must satisfy."},"outputSchema":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}],"description":"JSON Schema for the action's output (what downstream {{blocks.<id>.…}} bindings can read), or null for opaque/streamed results."}},"required":["name","description","feature","verb","kind","inputSchema","outputSchema"],"additionalProperties":false},"description":"Tools usable as an ACTION block's ref."},"filterCatalog":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"fields":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string","enum":["string","number","boolean","date"]}},"required":["name","type"],"additionalProperties":false}},"morphisms":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}}},"required":["fields","morphisms"],"additionalProperties":false},"description":"Objects a FILTER block's config.spec may range over: object name → readable fields (with primitive types) + follow morphisms (name → target object)."}},"required":["triggers","actions","filterCatalog"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["automations:read"]}],"x-guliel-feature":"automations","x-guliel-verb":"read","x-guliel-scope":"automations:read"}},"/api/automations/filter/preview":{"post":{"tags":["automations"],"summary":"Preview a filter spec — match count + sample rows","description":"Performs the `filter/preview` operation for the automations feature.\n\n**Scope:** `automations:read`  \n**Endpoint:** `POST /api/automations/filter/preview`","operationId":"automations.preview","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"organizationId":{"type":"string","minLength":1},"spec":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"A FilterSpec: { root, follows?, predicates?, aggregateBy?, extract, shape? }. root names a filterCatalog object; predicates are { object, field, op, value } with op one of eq|ne|gt|gte|lt|lte|in|nin|contains; extract entries are { as, path: \"Object.field\", fn?: \"sum\"|\"count\" }; shape is \"objects\" (default) | \"scalars\" | \"scalar\"."}},"required":["organizationId","spec"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of matching rows (capped at 1000)."},"sample":{"type":"array","items":{},"description":"First 5 shaped results (empty for shape: \"scalar\")."},"scalar":{"description":"The single value when the spec's shape is \"scalar\"."}},"required":["count","sample"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Number of matching rows (capped at 1000)."},"sample":{"type":"array","items":{},"description":"First 5 shaped results (empty for shape: \"scalar\")."},"scalar":{"description":"The single value when the spec's shape is \"scalar\"."}},"required":["count","sample"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["automations:read"]}],"x-guliel-feature":"automations","x-guliel-verb":"read","x-guliel-scope":"automations:read"}},"/api/bank-accounts":{"get":{"tags":["bank_accounts"],"summary":"List bank accounts","description":"Lists bank accounts the caller can see. Results are filtered by the caller's accessible organizations; many routes paginate via `page` and `limit`.\n\n**Scope:** `bank_accounts:read`  \n**Endpoint:** `GET /api/bank-accounts`","operationId":"bank_accounts.bank_accounts","parameters":[{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"bankAccounts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"accountName":{"type":"string"},"bankName":{"type":"string"},"accountNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"currencies":{"type":"array","items":{"type":"string"}},"branchCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"localBankCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"swiftCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"iban":{"anyOf":[{"type":"string"},{"type":"null"}]},"routingNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"bankAddress":{"anyOf":[{"type":"string"},{"type":"null"}]},"bankCountry":{"anyOf":[{"type":"string"},{"type":"null"}]},"isDefault":{"type":"boolean"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","accountName","bankName","accountNumber","currencies","branchCode","localBankCode","swiftCode","iban","routingNumber","bankAddress","bankCountry","isDefault","notes","createdAt","updatedAt"],"additionalProperties":false}}},"required":["bankAccounts"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["bank_accounts:read"]}],"x-guliel-feature":"bank_accounts","x-guliel-verb":"read","x-guliel-scope":"bank_accounts:read"},"post":{"tags":["bank_accounts"],"summary":"Create a bank account","description":"Creates a new bank account in the target organization. Returns the created record on success.\n\n**Scope:** `bank_accounts:write`  \n**Min role:** `CONTRIBUTOR` or higher  \n**Endpoint:** `POST /api/bank-accounts`","operationId":"bank_accounts.bank_accounts","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"organizationId":{"type":"string","minLength":1},"accountName":{"type":"string","minLength":1},"bankName":{"type":"string","minLength":1},"accountNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"currencies":{"default":["USD"],"type":"array","items":{"type":"string"}},"branchCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"localBankCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"swiftCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"iban":{"anyOf":[{"type":"string"},{"type":"null"}]},"routingNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"bankAddress":{"anyOf":[{"type":"string"},{"type":"null"}]},"bankCountry":{"anyOf":[{"type":"string"},{"type":"null"}]},"isDefault":{"default":false,"type":"boolean"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["organizationId","accountName","bankName","currencies","isDefault"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"accountName":{"type":"string"},"bankName":{"type":"string"},"accountNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"currencies":{"type":"array","items":{"type":"string"}},"branchCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"localBankCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"swiftCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"iban":{"anyOf":[{"type":"string"},{"type":"null"}]},"routingNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"bankAddress":{"anyOf":[{"type":"string"},{"type":"null"}]},"bankCountry":{"anyOf":[{"type":"string"},{"type":"null"}]},"isDefault":{"type":"boolean"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","accountName","bankName","accountNumber","currencies","branchCode","localBankCode","swiftCode","iban","routingNumber","bankAddress","bankCountry","isDefault","notes","createdAt","updatedAt"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"accountName":{"type":"string"},"bankName":{"type":"string"},"accountNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"currencies":{"type":"array","items":{"type":"string"}},"branchCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"localBankCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"swiftCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"iban":{"anyOf":[{"type":"string"},{"type":"null"}]},"routingNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"bankAddress":{"anyOf":[{"type":"string"},{"type":"null"}]},"bankCountry":{"anyOf":[{"type":"string"},{"type":"null"}]},"isDefault":{"type":"boolean"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","accountName","bankName","accountNumber","currencies","branchCode","localBankCode","swiftCode","iban","routingNumber","bankAddress","bankCountry","isDefault","notes","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["bank_accounts:write"]}],"x-guliel-feature":"bank_accounts","x-guliel-verb":"write","x-guliel-required-role":"CONTRIBUTOR","x-guliel-scope":"bank_accounts:write"}},"/api/bank-accounts/{id}":{"get":{"tags":["bank_accounts"],"summary":"Get a bank account","description":"Fetches a single bank account by id. Returns 404 if the bank account isn't in the caller's accessible organizations.\n\n**Scope:** `bank_accounts:read`  \n**Endpoint:** `GET /api/bank-accounts/{id}`","operationId":"bank_accounts.get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"accountName":{"type":"string"},"bankName":{"type":"string"},"accountNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"currencies":{"type":"array","items":{"type":"string"}},"branchCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"localBankCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"swiftCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"iban":{"anyOf":[{"type":"string"},{"type":"null"}]},"routingNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"bankAddress":{"anyOf":[{"type":"string"},{"type":"null"}]},"bankCountry":{"anyOf":[{"type":"string"},{"type":"null"}]},"isDefault":{"type":"boolean"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","accountName","bankName","accountNumber","currencies","branchCode","localBankCode","swiftCode","iban","routingNumber","bankAddress","bankCountry","isDefault","notes","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["bank_accounts:read"]}],"x-guliel-feature":"bank_accounts","x-guliel-verb":"read","x-guliel-scope":"bank_accounts:read"},"patch":{"tags":["bank_accounts"],"summary":"Update a bank account","description":"Updates an existing bank account. Only the fields present in the request body are changed; omitted fields stay as-is.\n\n**Scope:** `bank_accounts:write`  \n**Endpoint:** `PATCH /api/bank-accounts/{id}`","operationId":"bank_accounts.update","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"accountName":{"type":"string","minLength":1},"bankName":{"type":"string","minLength":1},"accountNumber":{"type":"string","minLength":1},"currencies":{"type":"array","items":{"type":"string"}},"branchCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"localBankCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"swiftCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"iban":{"anyOf":[{"type":"string"},{"type":"null"}]},"routingNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"bankAddress":{"anyOf":[{"type":"string"},{"type":"null"}]},"bankCountry":{"anyOf":[{"type":"string"},{"type":"null"}]},"isDefault":{"type":"boolean"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"accountName":{"type":"string"},"bankName":{"type":"string"},"accountNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"currencies":{"type":"array","items":{"type":"string"}},"branchCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"localBankCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"swiftCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"iban":{"anyOf":[{"type":"string"},{"type":"null"}]},"routingNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"bankAddress":{"anyOf":[{"type":"string"},{"type":"null"}]},"bankCountry":{"anyOf":[{"type":"string"},{"type":"null"}]},"isDefault":{"type":"boolean"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","accountName","bankName","accountNumber","currencies","branchCode","localBankCode","swiftCode","iban","routingNumber","bankAddress","bankCountry","isDefault","notes","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["bank_accounts:write"]}],"x-guliel-feature":"bank_accounts","x-guliel-verb":"write","x-guliel-scope":"bank_accounts:write"},"delete":{"tags":["bank_accounts"],"summary":"Delete a bank account","description":"Deletes the bank account. Some endpoints hard-delete the row, others soft-revoke (set `revokedAt`). Check the response shape.\n\n**Scope:** `bank_accounts:write`  \n**Endpoint:** `DELETE /api/bank-accounts/{id}`","operationId":"bank_accounts.delete","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true}},"required":["success"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["bank_accounts:write"]}],"x-guliel-feature":"bank_accounts","x-guliel-verb":"write","x-guliel-scope":"bank_accounts:write"}},"/api/companion/sessions":{"get":{"tags":["companion"],"summary":"List companion sessions","description":"Returns the `sessions` data for the companion sessions feature.\n\n**Scope:** `companion:read`  \n**Endpoint:** `GET /api/companion/sessions`","operationId":"companion.sessions","parameters":[{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"sessions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"icon":{"type":"string"},"lastActivityAt":{"type":"string"},"archived":{"type":"boolean"},"live":{"type":"boolean"}},"required":["id","title","icon","lastActivityAt","archived","live"],"additionalProperties":false}}},"required":["sessions"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["companion:read"]}],"x-guliel-feature":"companion","x-guliel-verb":"read","x-guliel-scope":"companion:read"},"post":{"tags":["companion"],"summary":"Start a companion session","description":"Performs the `sessions` operation for the companion sessions feature.\n\n**Scope:** `companion:write`  \n**Min role:** `CONTRIBUTOR` or higher  \n**Endpoint:** `POST /api/companion/sessions`","operationId":"companion.sessions","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"organizationId":{"type":"string","minLength":1},"sessionId":{"type":"string","minLength":1},"text":{"type":"string","minLength":1},"title":{"type":"string"},"icon":{"type":"string"},"attachments":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"size":{"type":"number"},"type":{"type":"string"},"storageKey":{"type":"string"}},"required":["name","size","type","storageKey"],"additionalProperties":false}}},"required":["organizationId","sessionId","text"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"sessionId":{"type":"string"},"turnRunId":{"type":"string"}},"required":["sessionId","turnRunId"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"sessionId":{"type":"string"},"turnRunId":{"type":"string"}},"required":["sessionId","turnRunId"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["companion:write"]}],"x-guliel-feature":"companion","x-guliel-verb":"write","x-guliel-required-role":"CONTRIBUTOR","x-guliel-scope":"companion:write"}},"/api/companion/sessions/{id}":{"get":{"tags":["companion"],"summary":"Get a companion session thread","description":"Returns every `sessions` row associated with the given companion session.\n\n**Scope:** `companion:read`  \n**Endpoint:** `GET /api/companion/sessions/{id}`","operationId":"companion.get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"title":{"type":"string"},"icon":{"type":"string"},"archived":{"type":"boolean"},"lastActivityAt":{"type":"string"},"createdAt":{"type":"string"},"messages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"role":{"type":"string","enum":["user","assistant"]},"index":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"text":{"anyOf":[{"type":"string"},{"type":"null"}]},"attachments":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"size":{"type":"number"},"type":{"type":"string"},"storageKey":{"type":"string"}},"required":["name","size","type","storageKey"],"additionalProperties":false}},{"type":"null"}]},"turnRunId":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"}},"required":["id","role","index","text","attachments","turnRunId","createdAt"],"additionalProperties":false}},"steps":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["TOOL","AGENT","WORKFLOW","TEXT"]},"ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"parentId":{"anyOf":[{"type":"string"},{"type":"null"}]},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"input":{},"output":{"anyOf":[{},{"type":"null"}]},"status":{"type":"string","enum":["PENDING","RUNNING","SUCCEEDED","FAILED","SKIPPED"]},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"turnRunId":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","kind","ref","parentId","order","input","output","status","error","turnRunId"],"additionalProperties":false}},"activeTurnRunId":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","organizationId","title","icon","archived","lastActivityAt","createdAt","messages","steps","activeTurnRunId"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["companion:read"]}],"x-guliel-feature":"companion","x-guliel-verb":"read","x-guliel-scope":"companion:read"},"patch":{"tags":["companion"],"summary":"Rename a companion session","description":"Mutates the `sessions` attached to the given companion session.\n\n**Scope:** `companion:write`  \n**Endpoint:** `PATCH /api/companion/sessions/{id}`","operationId":"companion.update","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","minLength":1},"title":{"type":"string","minLength":1}},"required":["id","title"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"icon":{"type":"string"},"lastActivityAt":{"type":"string"},"archived":{"type":"boolean"},"live":{"type":"boolean"}},"required":["id","title","icon","lastActivityAt","archived","live"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["companion:write"]}],"x-guliel-feature":"companion","x-guliel-verb":"write","x-guliel-scope":"companion:write"},"delete":{"tags":["companion"],"summary":"Delete a companion session","description":"Removes the association without deleting the underlying record.\n\n**Scope:** `companion:write`  \n**Endpoint:** `DELETE /api/companion/sessions/{id}`","operationId":"companion.delete","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true}},"required":["success"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["companion:write"]}],"x-guliel-feature":"companion","x-guliel-verb":"write","x-guliel-scope":"companion:write"}},"/api/companion/sessions/{id}/export":{"get":{"tags":["companion"],"summary":"Export a companion session transcript","description":"Returns every `sessions/export` row associated with the given companion session.\n\n**Scope:** `companion:read`  \n**Endpoint:** `GET /api/companion/sessions/{id}/export`","operationId":"companion.export","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["companion:read"]}],"x-guliel-feature":"companion","x-guliel-verb":"read","x-guliel-scope":"companion:read"}},"/api/companion/sessions/{id}/messages":{"post":{"tags":["companion"],"summary":"Send a companion message","description":"Creates a new `sessions/messages` attached to the given companion session.\n\n**Scope:** `companion:write`  \n**Min role:** `CONTRIBUTOR` or higher  \n**Endpoint:** `POST /api/companion/sessions/{id}/messages`","operationId":"companion.messages","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","minLength":1},"text":{"type":"string","minLength":1},"attachments":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"size":{"type":"number"},"type":{"type":"string"},"storageKey":{"type":"string"}},"required":["name","size","type","storageKey"],"additionalProperties":false}}},"required":["id","text"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"turnRunId":{"type":"string"}},"required":["turnRunId"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"turnRunId":{"type":"string"}},"required":["turnRunId"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["companion:write"]}],"x-guliel-feature":"companion","x-guliel-verb":"write","x-guliel-required-role":"CONTRIBUTOR","x-guliel-scope":"companion:write"}},"/api/companion/sessions/{id}/runlog":{"get":{"tags":["companion"],"summary":"Get a companion session run log","description":"Returns every `sessions/runlog` row associated with the given companion session.\n\n**Scope:** `companion:read`  \n**Endpoint:** `GET /api/companion/sessions/{id}/runlog`","operationId":"companion.runlog","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."},{"name":"page","in":"query","required":true,"schema":{"default":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"name":"limit","in":"query","required":true,"schema":{"default":50,"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"steps":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["TOOL","AGENT","WORKFLOW","TEXT"]},"ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"parentId":{"anyOf":[{"type":"string"},{"type":"null"}]},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"input":{},"output":{"anyOf":[{},{"type":"null"}]},"status":{"type":"string","enum":["PENDING","RUNNING","SUCCEEDED","FAILED","SKIPPED"]},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"turnRunId":{"type":"string"}},"required":["id","kind","ref","parentId","order","input","output","status","error","turnRunId"],"additionalProperties":false}},"pagination":{"type":"object","properties":{"page":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"totalPages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["page","limit","total","totalPages"],"additionalProperties":false}},"required":["steps","pagination"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["companion:read"]}],"x-guliel-feature":"companion","x-guliel-verb":"read","x-guliel-scope":"companion:read"}},"/api/companion/sessions/{id}/stream":{"get":{"tags":["companion"],"summary":"Stream a companion turn","description":"Returns every `sessions/stream` row associated with the given companion session.\n\n**Scope:** `companion:read`  \n**Endpoint:** `GET /api/companion/sessions/{id}/stream`","operationId":"companion.stream","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."},{"name":"lastEventId","in":"query","required":false,"schema":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["companion:read"]}],"x-guliel-feature":"companion","x-guliel-verb":"read","x-guliel-scope":"companion:read"}},"/api/companion/turns/{id}":{"get":{"tags":["companion"],"summary":"Get a companion turn ledger","description":"Returns every `turns` row associated with the given companion session.\n\n**Scope:** `companion:read`  \n**Endpoint:** `GET /api/companion/turns/{id}`","operationId":"companion.get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."},{"name":"afterSeq","in":"query","required":false,"schema":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"turnRunId":{"type":"string"},"sessionId":{"type":"string"},"status":{"type":"string","enum":["RUNNING","SUCCEEDED","FAILED","CANCELLED"]},"startedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"finishedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"steps":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["TOOL","AGENT","WORKFLOW","TEXT"]},"ref":{"anyOf":[{"type":"string"},{"type":"null"}]},"parentId":{"anyOf":[{"type":"string"},{"type":"null"}]},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"input":{},"output":{"anyOf":[{},{"type":"null"}]},"status":{"type":"string","enum":["PENDING","RUNNING","SUCCEEDED","FAILED","SKIPPED"]},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"turnRunId":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","kind","ref","parentId","order","input","output","status","error","turnRunId"],"additionalProperties":false}},"tokens":{"type":"array","items":{"type":"object","properties":{"seq":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"stepId":{"anyOf":[{"type":"string"},{"type":"null"}]},"delta":{"type":"string"}},"required":["seq","stepId","delta"],"additionalProperties":false}}},"required":["turnRunId","sessionId","status","startedAt","finishedAt","error","steps","tokens"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["companion:read"]}],"x-guliel-feature":"companion","x-guliel-verb":"read","x-guliel-scope":"companion:read"}},"/api/companion/turns/{id}/cancel":{"post":{"tags":["companion"],"summary":"Stop (cancel) a running companion turn","description":"Creates a new `turns/cancel` attached to the given companion session.\n\n**Scope:** `companion:write`  \n**Min role:** `CONTRIBUTOR` or higher  \n**Endpoint:** `POST /api/companion/turns/{id}/cancel`","operationId":"companion.cancel","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","minLength":1}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"}},"required":["id","status"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"}},"required":["id","status"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["companion:write"]}],"x-guliel-feature":"companion","x-guliel-verb":"write","x-guliel-required-role":"CONTRIBUTOR","x-guliel-scope":"companion:write"}},"/api/customers":{"get":{"tags":["customers"],"summary":"List customers","description":"Lists customers the caller can see. Results are filtered by the caller's accessible organizations; many routes paginate via `page` and `limit`.\n\n**Scope:** `customers:read`  \n**Endpoint:** `GET /api/customers`","operationId":"customers.customers","parameters":[{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}},{"name":"page","in":"query","required":true,"schema":{"default":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"name":"limit","in":"query","required":true,"schema":{"default":10,"type":"integer","minimum":1,"maximum":100}},{"name":"search","in":"query","required":true,"schema":{"default":"","type":"string"}},{"name":"inSystem","in":"query","required":false,"schema":{"anyOf":[{"type":"string","const":"true"},{"type":"string","const":"false"},{"type":"string","const":""}]}},{"name":"kind","in":"query","required":false,"schema":{"type":"string","enum":["ORGANIZATION","INDIVIDUAL"]}},{"name":"sortBy","in":"query","required":true,"schema":{"default":"createdAt","type":"string","enum":["name","email","createdAt","updatedAt"]}},{"name":"sortOrder","in":"query","required":true,"schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"customers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"registrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"defaultCurrencies":{"type":"array","items":{"type":"string"}},"organizationId":{"type":"string"},"kind":{"anyOf":[{"type":"string","enum":["ORGANIZATION","INDIVIDUAL"]},{"type":"null"}],"description":"Which party kind this counterparty edge points at."},"displayName":{"type":"string","description":"Resolved through the consolidation morphism — from the linked Organization or Individual."},"displayAddress":{"anyOf":[{"type":"string"},{"type":"null"}]},"displayCountry":{"anyOf":[{"type":"string"},{"type":"null"}]},"displayRegistrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"activeOrderCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"totalOrderCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"_count":{"type":"object","properties":{"invoices":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["invoices"],"additionalProperties":false},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","email","phone","address","country","registrationNumber","defaultCurrencies","organizationId","kind","displayName","displayAddress","displayCountry","displayRegistrationNumber","createdAt","updatedAt"],"additionalProperties":false}},"pagination":{"type":"object","properties":{"page":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"totalPages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["page","limit","total","totalPages"],"additionalProperties":false}},"required":["customers","pagination"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["customers:read"]}],"x-guliel-feature":"customers","x-guliel-verb":"read","x-guliel-scope":"customers:read"},"post":{"tags":["customers"],"summary":"Create a customer","description":"Creates a new customer in the target organization. Returns the created record on success.\n\n**Scope:** `customers:write`  \n**Min role:** `CONTRIBUTOR` or higher  \n**Endpoint:** `POST /api/customers`","operationId":"customers.customers","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"organizationId":{"type":"string","minLength":1},"name":{"type":"string","minLength":1},"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":""}]},"phone":{"type":"string"},"address":{"type":"string"},"country":{"type":"string","minLength":1},"registrationNumber":{"type":"string"},"defaultCurrencies":{"default":["USD"],"type":"array","items":{"type":"string"}},"kind":{"default":"ORGANIZATION","type":"string","enum":["ORGANIZATION","INDIVIDUAL"]}},"required":["organizationId","name","country","defaultCurrencies","kind"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"registrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"defaultCurrencies":{"type":"array","items":{"type":"string"}},"organizationId":{"type":"string"},"kind":{"anyOf":[{"type":"string","enum":["ORGANIZATION","INDIVIDUAL"]},{"type":"null"}],"description":"Which party kind this counterparty edge points at."},"displayName":{"type":"string","description":"Resolved through the consolidation morphism — from the linked Organization or Individual."},"displayAddress":{"anyOf":[{"type":"string"},{"type":"null"}]},"displayCountry":{"anyOf":[{"type":"string"},{"type":"null"}]},"displayRegistrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"activeOrderCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"totalOrderCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"_count":{"type":"object","properties":{"invoices":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["invoices"],"additionalProperties":false},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","email","phone","address","country","registrationNumber","defaultCurrencies","organizationId","kind","displayName","displayAddress","displayCountry","displayRegistrationNumber","createdAt","updatedAt"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"registrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"defaultCurrencies":{"type":"array","items":{"type":"string"}},"organizationId":{"type":"string"},"kind":{"anyOf":[{"type":"string","enum":["ORGANIZATION","INDIVIDUAL"]},{"type":"null"}],"description":"Which party kind this counterparty edge points at."},"displayName":{"type":"string","description":"Resolved through the consolidation morphism — from the linked Organization or Individual."},"displayAddress":{"anyOf":[{"type":"string"},{"type":"null"}]},"displayCountry":{"anyOf":[{"type":"string"},{"type":"null"}]},"displayRegistrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"activeOrderCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"totalOrderCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"_count":{"type":"object","properties":{"invoices":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["invoices"],"additionalProperties":false},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","email","phone","address","country","registrationNumber","defaultCurrencies","organizationId","kind","displayName","displayAddress","displayCountry","displayRegistrationNumber","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["customers:write"]}],"x-guliel-feature":"customers","x-guliel-verb":"write","x-guliel-required-role":"CONTRIBUTOR","x-guliel-scope":"customers:write"}},"/api/customers/{id}":{"get":{"tags":["customers"],"summary":"Get a customer","description":"Fetches a single customer by id. Returns 404 if the customer isn't in the caller's accessible organizations.\n\n**Scope:** `customers:read`  \n**Endpoint:** `GET /api/customers/{id}`","operationId":"customers.get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"registrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"defaultCurrencies":{"type":"array","items":{"type":"string"}},"organizationId":{"type":"string"},"kind":{"anyOf":[{"type":"string","enum":["ORGANIZATION","INDIVIDUAL"]},{"type":"null"}],"description":"Which party kind this counterparty edge points at."},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["PENDING","ACTIVE","INACTIVE"]},"displayName":{"type":"string"},"displayAddress":{"anyOf":[{"type":"string"},{"type":"null"}]},"displayCountry":{"anyOf":[{"type":"string"},{"type":"null"}]},"displayRegistrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"_count":{"type":"object","properties":{"invoices":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["invoices"],"additionalProperties":false},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","email","phone","address","country","registrationNumber","defaultCurrencies","organizationId","kind","notes","status","displayName","displayAddress","displayCountry","displayRegistrationNumber","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["customers:read"]}],"x-guliel-feature":"customers","x-guliel-verb":"read","x-guliel-scope":"customers:read"},"put":{"tags":["customers"],"summary":"Update a customer","description":"Replaces an existing customer. All required fields must be supplied — omitted fields revert to their schema defaults.\n\n**Scope:** `customers:write`  \n**Endpoint:** `PUT /api/customers/{id}`","operationId":"customers.update","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","minLength":1},"email":{"anyOf":[{"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":""}]},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"type":"string","minLength":1},"registrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"defaultCurrencies":{"type":"array","items":{"type":"string"}},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["PENDING","ACTIVE","INACTIVE"]}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"registrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"defaultCurrencies":{"type":"array","items":{"type":"string"}},"organizationId":{"type":"string"},"kind":{"anyOf":[{"type":"string","enum":["ORGANIZATION","INDIVIDUAL"]},{"type":"null"}],"description":"Which party kind this counterparty edge points at."},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["PENDING","ACTIVE","INACTIVE"]},"displayName":{"type":"string"},"displayAddress":{"anyOf":[{"type":"string"},{"type":"null"}]},"displayCountry":{"anyOf":[{"type":"string"},{"type":"null"}]},"displayRegistrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"_count":{"type":"object","properties":{"invoices":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["invoices"],"additionalProperties":false},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","email","phone","address","country","registrationNumber","defaultCurrencies","organizationId","kind","notes","status","displayName","displayAddress","displayCountry","displayRegistrationNumber","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["customers:write"]}],"x-guliel-feature":"customers","x-guliel-verb":"write","x-guliel-scope":"customers:write"},"patch":{"tags":["customers"],"summary":"Update a customer","description":"Updates an existing customer. Only the fields present in the request body are changed; omitted fields stay as-is.\n\n**Scope:** `customers:write`  \n**Endpoint:** `PATCH /api/customers/{id}`","operationId":"customers.update","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","minLength":1},"email":{"anyOf":[{"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":""}]},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"type":"string","minLength":1},"registrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"defaultCurrencies":{"type":"array","items":{"type":"string"}},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["PENDING","ACTIVE","INACTIVE"]}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"registrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"defaultCurrencies":{"type":"array","items":{"type":"string"}},"organizationId":{"type":"string"},"kind":{"anyOf":[{"type":"string","enum":["ORGANIZATION","INDIVIDUAL"]},{"type":"null"}],"description":"Which party kind this counterparty edge points at."},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["PENDING","ACTIVE","INACTIVE"]},"displayName":{"type":"string"},"displayAddress":{"anyOf":[{"type":"string"},{"type":"null"}]},"displayCountry":{"anyOf":[{"type":"string"},{"type":"null"}]},"displayRegistrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"_count":{"type":"object","properties":{"invoices":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["invoices"],"additionalProperties":false},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","email","phone","address","country","registrationNumber","defaultCurrencies","organizationId","kind","notes","status","displayName","displayAddress","displayCountry","displayRegistrationNumber","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["customers:write"]}],"x-guliel-feature":"customers","x-guliel-verb":"write","x-guliel-scope":"customers:write"},"delete":{"tags":["customers"],"summary":"Delete a customer","description":"Deletes the customer. Some endpoints hard-delete the row, others soft-revoke (set `revokedAt`). Check the response shape.\n\n**Scope:** `customers:write`  \n**Endpoint:** `DELETE /api/customers/{id}`","operationId":"customers.delete","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true}},"required":["success"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["customers:write"]}],"x-guliel-feature":"customers","x-guliel-verb":"write","x-guliel-scope":"customers:write"}},"/api/customers/{id}/recipients":{"get":{"tags":["customers"],"summary":"List recipients for a customer","description":"Returns every `recipients` row associated with the given customer.\n\n**Scope:** `customers:read`  \n**Endpoint:** `GET /api/customers/{id}/recipients`","operationId":"customers.recipients","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"customerId":{"type":"string"},"email":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","customerId","email","name","createdAt","updatedAt"],"additionalProperties":false}}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["customers:read"]}],"x-guliel-feature":"customers","x-guliel-verb":"read","x-guliel-scope":"customers:read"},"post":{"tags":["customers"],"summary":"Attach recipients to a customer","description":"Creates a new `recipients` attached to the given customer.\n\n**Scope:** `customers:write`  \n**Endpoint:** `POST /api/customers/{id}/recipients`","operationId":"customers.recipients","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"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"}},"required":["id","email"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"customerId":{"type":"string"},"email":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","customerId","email","name","createdAt","updatedAt"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"customerId":{"type":"string"},"email":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","customerId","email","name","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["customers:write"]}],"x-guliel-feature":"customers","x-guliel-verb":"write","x-guliel-scope":"customers:write"},"delete":{"tags":["customers"],"summary":"Detach recipients from a customer","description":"Removes the association without deleting the underlying record.\n\n**Scope:** `customers:write`  \n**Endpoint:** `DELETE /api/customers/{id}/recipients`","operationId":"customers.recipients","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."},{"name":"recipientId","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true}},"required":["success"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["customers:write"]}],"x-guliel-feature":"customers","x-guliel-verb":"write","x-guliel-scope":"customers:write"}},"/api/dashboard":{"get":{"tags":["invoices"],"summary":"List dashboard summaries","description":"Lists dashboard summaries the caller can see. Results are filtered by the caller's accessible organizations; many routes paginate via `page` and `limit`.\n\n**Scope:** `invoices:read`  \n**Endpoint:** `GET /api/dashboard`","operationId":"dashboard.dashboard","parameters":[{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}},{"name":"year","in":"query","required":true,"schema":{"default":2026,"type":"integer","minimum":2000,"maximum":2100}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"totalInvoices":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"totalRevenue":{"type":"number"},"outstandingAmount":{"type":"number"},"pendingAmount":{"type":"number"},"invoicesByStatus":{"type":"object","properties":{"draft":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unsent":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"sent":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"paid":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["draft","unsent","sent","paid"],"additionalProperties":false,"description":"Per-status counts of the org's invoices for the requested year."},"revenueByMonth":{"type":"array","items":{"type":"object","properties":{"month":{"type":"string"},"revenue":{"type":"number"},"sent":{"type":"number"},"unsent":{"type":"number"},"draft":{"type":"number"}},"required":["month","revenue","sent","unsent","draft"],"additionalProperties":false}},"revenueByCustomer":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"revenue":{"type":"number"},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["name","revenue","count"],"additionalProperties":false},"description":"Top customers by revenue, sorted descending. Currency-converted to `displayCurrency`. `count` is that client's own number of PAID invoices."},"growth":{"type":"number","description":"YoY revenue growth percentage."},"displayCurrency":{"type":"string","description":"Currency that all monetary fields are converted to (the organization's primary currency)."},"exchangeRateDate":{"type":"string","description":"Date of the FX-rate snapshot used for conversions."},"pendingPaymentsList":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"description":"Open invoices awaiting payment, sorted by due date."},"expenseTotal":{"type":"number"},"expensesByMonth":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"expensesByVendor":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"paidInvoicesCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"approvedExpensesCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"expenseGrowth":{"type":"number"},"netTotal":{"type":"number","description":"Revenue minus expenses, in displayCurrency."},"netGrowth":{"type":"number"},"marginPercent":{"type":"number"},"pendingExpensesTotal":{"type":"number"},"pendingExpensesCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"pendingExpensesGrowth":{"type":"number"},"cashFlowByMonth":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"lowStockItemsCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"activeItemsCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"fxIncomplete":{"description":"True when one or more source currencies could not be converted to `displayCurrency` (missing FX rate). Those amounts were summed at face value — totals are approximate. Surfaced in ALL environments (data quality, not a diagnostic).","type":"boolean"},"fxMissingCurrencies":{"description":"Source currencies that lacked a usable rate to `displayCurrency`. Present (and non-empty) iff `fxIncomplete` is true.","type":"array","items":{"type":"string"}},"_diagnostics":{"description":"Only present in non-production environments — surfaces errors that were caught and logged but didn't abort the response.","type":"array","items":{"type":"string"}}},"required":["totalInvoices","totalRevenue","outstandingAmount","pendingAmount","invoicesByStatus","revenueByMonth","revenueByCustomer","growth","displayCurrency","exchangeRateDate","pendingPaymentsList","expenseTotal","expensesByMonth","expensesByVendor","paidInvoicesCount","approvedExpensesCount","expenseGrowth","netTotal","netGrowth","marginPercent","pendingExpensesTotal","pendingExpensesCount","pendingExpensesGrowth","cashFlowByMonth","lowStockItemsCount","activeItemsCount"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["invoices:read"]}],"x-guliel-feature":"invoices","x-guliel-verb":"read","x-guliel-scope":"invoices:read"}},"/api/documents":{"get":{"tags":["invoices"],"summary":"List documents","description":"Lists documents the caller can see. Results are filtered by the caller's accessible organizations; many routes paginate via `page` and `limit`.\n\n**Scope:** `invoices:read`  \n**Endpoint:** `GET /api/documents`","operationId":"documents.documents","parameters":[{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}},{"name":"page","in":"query","required":true,"schema":{"default":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"name":"limit","in":"query","required":true,"schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["DRAFT","UNSENT","SENT","PAID"]}},{"name":"documentType","in":"query","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","required":true,"schema":{"default":"","type":"string"}},{"name":"customerId","in":"query","required":false,"schema":{"type":"string"}},{"name":"disputed","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}},{"name":"sortBy","in":"query","required":true,"schema":{"default":"issueDate","type":"string","enum":["issueDate","dueDate","total","status","documentNumber","customerName"]}},{"name":"sortOrder","in":"query","required":true,"schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"invoices":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"customerId":{"type":"string"},"documentType":{"type":"string"},"invoiceNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string"},"inDispute":{"type":"boolean"},"invoiceDate":{"type":"string"},"dueDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"currency":{"type":"string"},"exchangeRate":{"anyOf":[{"type":"number"},{"type":"null"}]},"subtotal":{"type":"number"},"taxAmount":{"type":"number"},"total":{"type":"number"},"paidAmount":{"type":"number"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"vatAllocationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"generatorVersion":{"type":"string"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"customer":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","email"],"additionalProperties":false},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"description":{"type":"string"},"quantity":{"type":"number"},"unitPrice":{"type":"number"},"amount":{"type":"number"}},"required":["id","description","quantity","unitPrice","amount"],"additionalProperties":false}},"payments":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"attachments":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"createdBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false},{"type":"null"}]}},"required":["id","organizationId","customerId","documentType","invoiceNumber","status","inDispute","invoiceDate","dueDate","currency","exchangeRate","subtotal","taxAmount","total","paidAmount","notes","vatAllocationNumber","generatorVersion","createdAt","updatedAt","customer","items","createdBy"],"additionalProperties":false}},"pagination":{"type":"object","properties":{"page":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"totalPages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["page","limit","total","totalPages"],"additionalProperties":false}},"required":["invoices","pagination"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["invoices:read"]}],"x-guliel-feature":"invoices","x-guliel-verb":"read","x-guliel-scope":"invoices:read"},"post":{"tags":["invoices"],"summary":"Create a document","description":"Creates a new document in the target organization. Returns the created record on success.\n\n**Scope:** `invoices:write`  \n**Min role:** `CONTRIBUTOR` or higher  \n**Endpoint:** `POST /api/documents`","operationId":"documents.documents","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"organizationId":{"type":"string","minLength":1},"customerId":{"type":"string","minLength":1},"bankAccountId":{"anyOf":[{"type":"string"},{"type":"null"}]},"currency":{"type":"string","minLength":1},"status":{"default":"DRAFT","type":"string","enum":["DRAFT","UNSENT","SENT","PAID"]},"documentType":{"default":"INVOICE","type":"string","enum":["INVOICE","RECEIPT","INVOICE_RECEIPT","PAYMENT_REQUEST"]},"dueDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"payUntil":{"anyOf":[{"type":"string"},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"itemId":{"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"type":"string","minLength":1},"quantity":{"type":"number","minimum":0},"unitPrice":{"type":"number","minimum":0},"amount":{"type":"number"}},"required":["id","description","quantity","unitPrice","amount"],"additionalProperties":false}},"subtotal":{"type":"number"},"taxRate":{"type":"number"},"taxAmount":{"type":"number"},"total":{"type":"number"},"countrySpecificData":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"paymentMethod":{"anyOf":[{"type":"string"},{"type":"null"}]},"paymentDate":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["organizationId","customerId","currency","status","documentType","items","subtotal","taxRate","taxAmount","total"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"customerId":{"type":"string"},"documentType":{"type":"string"},"invoiceNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string"},"inDispute":{"type":"boolean"},"invoiceDate":{"type":"string"},"dueDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"currency":{"type":"string"},"exchangeRate":{"anyOf":[{"type":"number"},{"type":"null"}]},"subtotal":{"type":"number"},"taxAmount":{"type":"number"},"total":{"type":"number"},"paidAmount":{"type":"number"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"vatAllocationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"generatorVersion":{"type":"string"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"customer":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","email"],"additionalProperties":false},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"description":{"type":"string"},"quantity":{"type":"number"},"unitPrice":{"type":"number"},"amount":{"type":"number"}},"required":["id","description","quantity","unitPrice","amount"],"additionalProperties":false}},"payments":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"attachments":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"createdBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false},{"type":"null"}]}},"required":["id","organizationId","customerId","documentType","invoiceNumber","status","inDispute","invoiceDate","dueDate","currency","exchangeRate","subtotal","taxAmount","total","paidAmount","notes","vatAllocationNumber","generatorVersion","createdAt","updatedAt","customer","items","createdBy"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"customerId":{"type":"string"},"documentType":{"type":"string"},"invoiceNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string"},"inDispute":{"type":"boolean"},"invoiceDate":{"type":"string"},"dueDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"currency":{"type":"string"},"exchangeRate":{"anyOf":[{"type":"number"},{"type":"null"}]},"subtotal":{"type":"number"},"taxAmount":{"type":"number"},"total":{"type":"number"},"paidAmount":{"type":"number"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"vatAllocationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"generatorVersion":{"type":"string"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"customer":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","email"],"additionalProperties":false},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"description":{"type":"string"},"quantity":{"type":"number"},"unitPrice":{"type":"number"},"amount":{"type":"number"}},"required":["id","description","quantity","unitPrice","amount"],"additionalProperties":false}},"payments":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"attachments":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"createdBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false},{"type":"null"}]}},"required":["id","organizationId","customerId","documentType","invoiceNumber","status","inDispute","invoiceDate","dueDate","currency","exchangeRate","subtotal","taxAmount","total","paidAmount","notes","vatAllocationNumber","generatorVersion","createdAt","updatedAt","customer","items","createdBy"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["invoices:write"]}],"x-guliel-feature":"invoices","x-guliel-verb":"write","x-guliel-required-role":"CONTRIBUTOR","x-guliel-scope":"invoices:write"}},"/api/documents/{id}":{"get":{"tags":["invoices"],"summary":"Get a document","description":"Fetches a single document by id. Returns 404 if the document isn't in the caller's accessible organizations.\n\n**Scope:** `invoices:read`  \n**Endpoint:** `GET /api/documents/{id}`","operationId":"documents.get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"customerId":{"type":"string"},"bankAccountId":{"anyOf":[{"type":"string"},{"type":"null"}]},"invoiceNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"documentType":{"type":"string"},"status":{"type":"string"},"direction":{"type":"string"},"inDispute":{"type":"boolean"},"currency":{"type":"string"},"exchangeRate":{"anyOf":[{"type":"number"},{"type":"null"}]},"issueDate":{"type":"string"},"dueDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"payUntil":{"anyOf":[{"type":"string"},{"type":"null"}]},"paymentMethod":{"anyOf":[{"type":"string"},{"type":"null"}]},"paymentDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"receiptNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"subtotal":{"type":"number"},"taxRate":{"anyOf":[{"type":"number"},{"type":"null"}]},"taxAmount":{"type":"number"},"total":{"type":"number"},"paidAmount":{"type":"number"},"payments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"amount":{"type":"number"},"allocated":{"type":"number"},"paidAt":{"type":"string"},"method":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","amount","allocated","paidAt","method"],"additionalProperties":false}},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"generatorVersion":{"type":"string"},"vatAllocationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"countrySpecificData":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"organization":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"country":{"type":"string"},"registrationNumber":{"type":"string"},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"icon":{"anyOf":[{"type":"string"},{"type":"null"}]},"countrySpecificData":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]}},"required":["id","name","country","registrationNumber","address","icon","countrySpecificData"],"additionalProperties":false},{"type":"null"}]},"customer":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"registrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","email","phone","address","country","registrationNumber"],"additionalProperties":false},{"type":"null"}]},"bankAccount":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"createdBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","customerId","bankAccountId","invoiceNumber","documentType","status","direction","inDispute","currency","exchangeRate","issueDate","dueDate","payUntil","paymentMethod","paymentDate","receiptNumber","subtotal","taxRate","taxAmount","total","paidAmount","payments","notes","generatorVersion","vatAllocationNumber","countrySpecificData","items","organization","customer","bankAccount","createdBy","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["invoices:read"]}],"x-guliel-feature":"invoices","x-guliel-verb":"read","x-guliel-scope":"invoices:read"},"put":{"tags":["invoices"],"summary":"Update a document","description":"Replaces an existing document. All required fields must be supplied — omitted fields revert to their schema defaults.\n\n**Scope:** `invoices:write`  \n**Endpoint:** `PUT /api/documents/{id}`","operationId":"documents.update","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"customerId":{"type":"string","minLength":1},"bankAccountId":{"anyOf":[{"type":"string"},{"type":"null"}]},"currency":{"type":"string","minLength":1},"status":{"type":"string","enum":["DRAFT","UNSENT","SENT","PAID"]},"documentType":{"type":"string","enum":["INVOICE","RECEIPT","INVOICE_RECEIPT","PAYMENT_REQUEST"]},"dueDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"payUntil":{"anyOf":[{"type":"string"},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"itemId":{"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"type":"string","minLength":1},"quantity":{"type":"number","minimum":0},"unitPrice":{"type":"number","minimum":0},"amount":{"type":"number"}},"required":["id","description","quantity","unitPrice","amount"],"additionalProperties":false}},"subtotal":{"type":"number"},"taxRate":{"type":"number"},"taxAmount":{"type":"number"},"total":{"type":"number"},"countrySpecificData":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"clearReceiptInfo":{"type":"boolean"},"paymentMethod":{"anyOf":[{"type":"string"},{"type":"null"}]},"paymentDate":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"customerId":{"type":"string"},"bankAccountId":{"anyOf":[{"type":"string"},{"type":"null"}]},"invoiceNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"documentType":{"type":"string"},"status":{"type":"string"},"direction":{"type":"string"},"inDispute":{"type":"boolean"},"currency":{"type":"string"},"exchangeRate":{"anyOf":[{"type":"number"},{"type":"null"}]},"issueDate":{"type":"string"},"dueDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"payUntil":{"anyOf":[{"type":"string"},{"type":"null"}]},"paymentMethod":{"anyOf":[{"type":"string"},{"type":"null"}]},"paymentDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"receiptNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"subtotal":{"type":"number"},"taxRate":{"anyOf":[{"type":"number"},{"type":"null"}]},"taxAmount":{"type":"number"},"total":{"type":"number"},"paidAmount":{"type":"number"},"payments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"amount":{"type":"number"},"allocated":{"type":"number"},"paidAt":{"type":"string"},"method":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","amount","allocated","paidAt","method"],"additionalProperties":false}},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"generatorVersion":{"type":"string"},"vatAllocationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"countrySpecificData":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"organization":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"country":{"type":"string"},"registrationNumber":{"type":"string"},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"icon":{"anyOf":[{"type":"string"},{"type":"null"}]},"countrySpecificData":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]}},"required":["id","name","country","registrationNumber","address","icon","countrySpecificData"],"additionalProperties":false},{"type":"null"}]},"customer":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"registrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","email","phone","address","country","registrationNumber"],"additionalProperties":false},{"type":"null"}]},"bankAccount":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"createdBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","customerId","bankAccountId","invoiceNumber","documentType","status","direction","inDispute","currency","exchangeRate","issueDate","dueDate","payUntil","paymentMethod","paymentDate","receiptNumber","subtotal","taxRate","taxAmount","total","paidAmount","payments","notes","generatorVersion","vatAllocationNumber","countrySpecificData","items","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["invoices:write"]}],"x-guliel-feature":"invoices","x-guliel-verb":"write","x-guliel-scope":"invoices:write"},"patch":{"tags":["invoices"],"summary":"Update a document","description":"Updates an existing document. Only the fields present in the request body are changed; omitted fields stay as-is.\n\n**Scope:** `invoices:write`  \n**Endpoint:** `PATCH /api/documents/{id}`","operationId":"documents.update","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"customerId":{"type":"string","minLength":1},"bankAccountId":{"anyOf":[{"type":"string"},{"type":"null"}]},"currency":{"type":"string","minLength":1},"status":{"type":"string","enum":["DRAFT","UNSENT","SENT","PAID"]},"documentType":{"type":"string","enum":["INVOICE","RECEIPT","INVOICE_RECEIPT","PAYMENT_REQUEST"]},"dueDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"payUntil":{"anyOf":[{"type":"string"},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"itemId":{"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"type":"string","minLength":1},"quantity":{"type":"number","minimum":0},"unitPrice":{"type":"number","minimum":0},"amount":{"type":"number"}},"required":["id","description","quantity","unitPrice","amount"],"additionalProperties":false}},"subtotal":{"type":"number"},"taxRate":{"type":"number"},"taxAmount":{"type":"number"},"total":{"type":"number"},"countrySpecificData":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"clearReceiptInfo":{"type":"boolean"},"paymentMethod":{"anyOf":[{"type":"string"},{"type":"null"}]},"paymentDate":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"customerId":{"type":"string"},"bankAccountId":{"anyOf":[{"type":"string"},{"type":"null"}]},"invoiceNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"documentType":{"type":"string"},"status":{"type":"string"},"direction":{"type":"string"},"inDispute":{"type":"boolean"},"currency":{"type":"string"},"exchangeRate":{"anyOf":[{"type":"number"},{"type":"null"}]},"issueDate":{"type":"string"},"dueDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"payUntil":{"anyOf":[{"type":"string"},{"type":"null"}]},"paymentMethod":{"anyOf":[{"type":"string"},{"type":"null"}]},"paymentDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"receiptNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"subtotal":{"type":"number"},"taxRate":{"anyOf":[{"type":"number"},{"type":"null"}]},"taxAmount":{"type":"number"},"total":{"type":"number"},"paidAmount":{"type":"number"},"payments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"amount":{"type":"number"},"allocated":{"type":"number"},"paidAt":{"type":"string"},"method":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","amount","allocated","paidAt","method"],"additionalProperties":false}},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"generatorVersion":{"type":"string"},"vatAllocationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"countrySpecificData":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"organization":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"country":{"type":"string"},"registrationNumber":{"type":"string"},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"icon":{"anyOf":[{"type":"string"},{"type":"null"}]},"countrySpecificData":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]}},"required":["id","name","country","registrationNumber","address","icon","countrySpecificData"],"additionalProperties":false},{"type":"null"}]},"customer":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"registrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","email","phone","address","country","registrationNumber"],"additionalProperties":false},{"type":"null"}]},"bankAccount":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"createdBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","customerId","bankAccountId","invoiceNumber","documentType","status","direction","inDispute","currency","exchangeRate","issueDate","dueDate","payUntil","paymentMethod","paymentDate","receiptNumber","subtotal","taxRate","taxAmount","total","paidAmount","payments","notes","generatorVersion","vatAllocationNumber","countrySpecificData","items","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["invoices:write"]}],"x-guliel-feature":"invoices","x-guliel-verb":"write","x-guliel-scope":"invoices:write"},"delete":{"tags":["invoices"],"summary":"Delete a document","description":"Deletes the document. Some endpoints hard-delete the row, others soft-revoke (set `revokedAt`). Check the response shape.\n\n**Scope:** `invoices:write`  \n**Endpoint:** `DELETE /api/documents/{id}`","operationId":"documents.delete","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true}},"required":["success"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["invoices:write"]}],"x-guliel-feature":"invoices","x-guliel-verb":"write","x-guliel-scope":"invoices:write"}},"/api/documents/{id}/clearance":{"get":{"tags":["invoices"],"summary":"List clearance for a document","description":"Returns every `clearance` row associated with the given document.\n\n**Scope:** `invoices:read`  \n**Endpoint:** `GET /api/documents/{id}/clearance`","operationId":"documents.clearance","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Country-specific clearance status — fields depend on the country handler (Israel returns `status`, `vatAllocationNumber`, `submittedAt`, etc.). See `clearanceService.getClearanceStatus`."}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["invoices:read"]}],"x-guliel-feature":"invoices","x-guliel-verb":"read","x-guliel-scope":"invoices:read"},"post":{"tags":["invoices"],"summary":"Attach clearance to a document","description":"Creates a new `clearance` attached to the given document.\n\n**Scope:** `invoices:write`  \n**Endpoint:** `POST /api/documents/{id}/clearance`","operationId":"documents.clearance","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"action":{"type":"string","enum":["submit","retry"]}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","description":"True iff the country handler reports APPROVED on this submission."},"result":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Full clearance result from the country handler."}},"required":["success","result"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","description":"True iff the country handler reports APPROVED on this submission."},"result":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Full clearance result from the country handler."}},"required":["success","result"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["invoices:write"]}],"x-guliel-feature":"invoices","x-guliel-verb":"write","x-guliel-scope":"invoices:write"}},"/api/documents/{id}/events":{"get":{"tags":["invoices"],"summary":"List events for a document","description":"Returns every `events` row associated with the given document.\n\n**Scope:** `invoices:read`  \n**Endpoint:** `GET /api/documents/{id}/events`","operationId":"documents.events","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."},{"name":"page","in":"query","required":true,"schema":{"default":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"name":"limit","in":"query","required":true,"schema":{"default":50,"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"events":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"documentId":{"type":"string"},"organizationId":{"type":"string"},"type":{"type":"string","description":"DocumentEventType — see DOCUMENT_EVENTS.md §4."},"actorUserId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"null = a system event."},"actor":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false},{"type":"null"}]},"payload":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}],"description":"Event-specific data — shape depends on `type` (§4)."},"createdAt":{"type":"string"}},"required":["id","documentId","organizationId","type","actorUserId","actor","payload","createdAt"],"additionalProperties":false}},"pagination":{"type":"object","properties":{"page":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"totalPages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["page","limit","total","totalPages"],"additionalProperties":false}},"required":["events","pagination"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["invoices:read"]}],"x-guliel-feature":"invoices","x-guliel-verb":"read","x-guliel-scope":"invoices:read"},"post":{"tags":["invoices"],"summary":"Attach events to a document","description":"Creates a new `events` attached to the given document.\n\n**Scope:** `invoices:write`  \n**Endpoint:** `POST /api/documents/{id}/events`","operationId":"documents.events","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["DISPUTED","DISPUTE_COUNTERED","DISPUTE_RESOLVED","COMMENTED","APPROVED","REJECTED"]},"payload":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["id","type"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"documentId":{"type":"string"},"organizationId":{"type":"string"},"type":{"type":"string","description":"DocumentEventType — see DOCUMENT_EVENTS.md §4."},"actorUserId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"null = a system event."},"actor":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false},{"type":"null"}]},"payload":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}],"description":"Event-specific data — shape depends on `type` (§4)."},"createdAt":{"type":"string"}},"required":["id","documentId","organizationId","type","actorUserId","actor","payload","createdAt"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"documentId":{"type":"string"},"organizationId":{"type":"string"},"type":{"type":"string","description":"DocumentEventType — see DOCUMENT_EVENTS.md §4."},"actorUserId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"null = a system event."},"actor":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false},{"type":"null"}]},"payload":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}],"description":"Event-specific data — shape depends on `type` (§4)."},"createdAt":{"type":"string"}},"required":["id","documentId","organizationId","type","actorUserId","actor","payload","createdAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["invoices:write"]}],"x-guliel-feature":"invoices","x-guliel-verb":"write","x-guliel-scope":"invoices:write"}},"/api/documents/{id}/manual-allocation":{"post":{"tags":["invoices"],"summary":"Attach manual allocation to a document","description":"Creates a new `manual-allocation` attached to the given document.\n\n**Scope:** `invoices:write`  \n**Endpoint:** `POST /api/documents/{id}/manual-allocation`","operationId":"documents.manual_allocation","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"allocationNumber":{"type":"string","minLength":9}},"required":["id","allocationNumber"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true},"allocationNumber":{"type":"string","description":"Digits-only allocation number after stripping non-digit characters."}},"required":["success","allocationNumber"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true},"allocationNumber":{"type":"string","description":"Digits-only allocation number after stripping non-digit characters."}},"required":["success","allocationNumber"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["invoices:write"]}],"x-guliel-feature":"invoices","x-guliel-verb":"write","x-guliel-scope":"invoices:write"}},"/api/documents/{id}/mark-paid":{"post":{"tags":["invoices"],"summary":"Update the document status","description":"Mutates the state machine of the document. Some transitions are restricted by role.\n\n**Scope:** `invoices:write`  \n**Endpoint:** `POST /api/documents/{id}/mark-paid`","operationId":"documents.mark_paid","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"paymentDate":{"type":"string"},"paymentMethod":{"type":"string"},"generateReceipt":{"type":"boolean"},"generateTaxFreeReceipt":{"type":"boolean"},"sendReceiptEmail":{"default":false,"type":"boolean"}},"required":["id","paymentDate","paymentMethod","sendReceiptEmail"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Updated invoice row plus `receiptNumber`, `emailsSent`, `emailsFailed` counts. See /api/documents/[id] GET for the canonical invoice shape."}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Updated invoice row plus `receiptNumber`, `emailsSent`, `emailsFailed` counts. See /api/documents/[id] GET for the canonical invoice shape."}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["invoices:write"]}],"x-guliel-feature":"invoices","x-guliel-verb":"write","x-guliel-scope":"invoices:write"}},"/api/documents/{id}/send":{"post":{"tags":["invoices"],"summary":"Send a document by email","description":"Renders the document as a PDF, attaches it, and emails it to the configured recipients.\n\n**Scope:** `invoices:write`  \n**Endpoint:** `POST /api/documents/{id}/send`","operationId":"documents.send","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true},"sent":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"failed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"totalRecipients":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["success","sent","failed","totalRecipients"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true},"sent":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"failed":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"totalRecipients":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["success","sent","failed","totalRecipients"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["invoices:write"]}],"x-guliel-feature":"invoices","x-guliel-verb":"write","x-guliel-scope":"invoices:write"}},"/api/exchange-rates/refresh":{"post":{"tags":["settings"],"summary":"Run refresh (exchange rates)","description":"Performs the `refresh` operation for the exchange rates feature.\n\n**Scope:** `settings:write`  \n**Endpoint:** `POST /api/exchange-rates/refresh`","operationId":"exchange_rates.refresh","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{},"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"message":{"type":"string"},"date":{"type":"string","description":"ISO date of the FX snapshot that's now active."},"ratesCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many currency pairs were refreshed."}},"required":["message","date","ratesCount"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"message":{"type":"string"},"date":{"type":"string","description":"ISO date of the FX snapshot that's now active."},"ratesCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many currency pairs were refreshed."}},"required":["message","date","ratesCount"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["settings:write"]}],"x-guliel-feature":"settings","x-guliel-verb":"write","x-guliel-scope":"settings:write"}},"/api/expense-categories":{"get":{"tags":["expenses"],"summary":"List expense categories","description":"Lists expense categories the caller can see. Results are filtered by the caller's accessible organizations; many routes paginate via `page` and `limit`.\n\n**Scope:** `expenses:read`  \n**Endpoint:** `GET /api/expense-categories`","operationId":"expense_categories.expense_categories","parameters":[{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"categories":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"name":{"type":"string"},"color":{"anyOf":[{"type":"string"},{"type":"null"}]},"isDefault":{"type":"boolean"},"_count":{"type":"object","properties":{"expenses":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["expenses"],"additionalProperties":false},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","name","color","isDefault","createdAt","updatedAt"],"additionalProperties":false}}},"required":["categories"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["expenses:read"]}],"x-guliel-feature":"expenses","x-guliel-verb":"read","x-guliel-scope":"expenses:read"},"post":{"tags":["expenses"],"summary":"Create an expense category","description":"Creates a new expense category in the target organization. Returns the created record on success.\n\n**Scope:** `expenses:write`  \n**Min role:** `CONTRIBUTOR` or higher  \n**Endpoint:** `POST /api/expense-categories`","operationId":"expense_categories.expense_categories","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"organizationId":{"type":"string","minLength":1},"name":{"type":"string","minLength":1},"color":{"type":"string"}},"required":["organizationId","name"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"name":{"type":"string"},"color":{"anyOf":[{"type":"string"},{"type":"null"}]},"isDefault":{"type":"boolean"},"_count":{"type":"object","properties":{"expenses":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["expenses"],"additionalProperties":false},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","name","color","isDefault","createdAt","updatedAt"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"name":{"type":"string"},"color":{"anyOf":[{"type":"string"},{"type":"null"}]},"isDefault":{"type":"boolean"},"_count":{"type":"object","properties":{"expenses":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["expenses"],"additionalProperties":false},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","name","color","isDefault","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["expenses:write"]}],"x-guliel-feature":"expenses","x-guliel-verb":"write","x-guliel-required-role":"CONTRIBUTOR","x-guliel-scope":"expenses:write"}},"/api/expense-categories/{id}":{"put":{"tags":["expenses"],"summary":"Update an expense category","description":"Replaces an existing expense category. All required fields must be supplied — omitted fields revert to their schema defaults.\n\n**Scope:** `expenses:write`  \n**Endpoint:** `PUT /api/expense-categories/{id}`","operationId":"expense_categories.update","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","minLength":1},"color":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"name":{"type":"string"},"color":{"anyOf":[{"type":"string"},{"type":"null"}]},"isDefault":{"type":"boolean"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","name","color","isDefault","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["expenses:write"]}],"x-guliel-feature":"expenses","x-guliel-verb":"write","x-guliel-scope":"expenses:write"},"patch":{"tags":["expenses"],"summary":"Update an expense category","description":"Updates an existing expense category. Only the fields present in the request body are changed; omitted fields stay as-is.\n\n**Scope:** `expenses:write`  \n**Endpoint:** `PATCH /api/expense-categories/{id}`","operationId":"expense_categories.update","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","minLength":1},"color":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"name":{"type":"string"},"color":{"anyOf":[{"type":"string"},{"type":"null"}]},"isDefault":{"type":"boolean"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","name","color","isDefault","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["expenses:write"]}],"x-guliel-feature":"expenses","x-guliel-verb":"write","x-guliel-scope":"expenses:write"},"delete":{"tags":["expenses"],"summary":"Delete an expense category","description":"Deletes the expense category. Some endpoints hard-delete the row, others soft-revoke (set `revokedAt`). Check the response shape.\n\n**Scope:** `expenses:write`  \n**Endpoint:** `DELETE /api/expense-categories/{id}`","operationId":"expense_categories.delete","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true}},"required":["success"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["expenses:write"]}],"x-guliel-feature":"expenses","x-guliel-verb":"write","x-guliel-scope":"expenses:write"}},"/api/expenses":{"get":{"tags":["expenses"],"summary":"List expenses","description":"Lists expenses the caller can see. Results are filtered by the caller's accessible organizations; many routes paginate via `page` and `limit`.\n\n**Scope:** `expenses:read`  \n**Endpoint:** `GET /api/expenses`","operationId":"expenses.expenses","parameters":[{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}},{"name":"page","in":"query","required":true,"schema":{"default":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"name":"limit","in":"query","required":true,"schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"search","in":"query","required":true,"schema":{"default":"","type":"string"}},{"name":"categoryId","in":"query","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"source","in":"query","required":false,"schema":{"type":"string"}},{"name":"dateFrom","in":"query","required":false,"schema":{"type":"string"}},{"name":"dateTo","in":"query","required":false,"schema":{"type":"string"}},{"name":"minAmount","in":"query","required":false,"schema":{"type":"string"}},{"name":"maxAmount","in":"query","required":false,"schema":{"type":"string"}},{"name":"customerId","in":"query","required":false,"schema":{"type":"string"}},{"name":"sortBy","in":"query","required":true,"schema":{"default":"date","type":"string","enum":["date","amount","vendor","createdAt"]}},{"name":"sortOrder","in":"query","required":true,"schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"expenses":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount":{"type":"number"},"currency":{"type":"string"},"date":{"type":"string"},"category":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]},"vendor":{"anyOf":[{"type":"string"},{"type":"null"}]},"paymentMethod":{"anyOf":[{"type":"string"},{"type":"null"}]},"paidAmount":{"type":"number"},"openBalance":{"type":"number"},"payments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"amount":{"type":"number"},"allocated":{"type":"number"},"paidAt":{"type":"string"},"method":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","amount","allocated","paidAt","method"],"additionalProperties":false}},"source":{"type":"string"},"status":{"type":"string"},"attachments":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"customers":{"type":"array","items":{"type":"object","properties":{"customerId":{"type":"string"},"customer":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]}},"required":["customerId","customer"],"additionalProperties":false}},"createdBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","description","amount","currency","date","category","vendor","paymentMethod","paidAmount","openBalance","payments","source","status","createdBy","createdAt","updatedAt"],"additionalProperties":false}},"pagination":{"type":"object","properties":{"page":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"totalPages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["page","limit","total","totalPages"],"additionalProperties":false}},"required":["expenses","pagination"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["expenses:read"]}],"x-guliel-feature":"expenses","x-guliel-verb":"read","x-guliel-scope":"expenses:read"},"post":{"tags":["expenses"],"summary":"Create an expense","description":"Creates a new expense in the target organization. Returns the created record on success.\n\n**Scope:** `expenses:write`  \n**Min role:** `CONTRIBUTOR` or higher  \n**Endpoint:** `POST /api/expenses`","operationId":"expenses.expenses","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"organizationId":{"type":"string","minLength":1},"title":{"type":"string"},"vendor":{"type":"string"},"amount":{"type":"number","exclusiveMinimum":0},"currency":{"type":"string","minLength":1},"date":{"type":"string","minLength":1},"categoryId":{"type":"string"},"notes":{"type":"string"},"taxAmount":{"type":"number"},"taxRate":{"type":"number"},"paymentMethod":{"type":"string"},"source":{"default":"MANUAL","type":"string","enum":["MANUAL","SCAN","EMAIL"]},"customerIds":{"type":"array","items":{"type":"string"}}},"required":["organizationId","amount","currency","date","source"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount":{"type":"number"},"currency":{"type":"string"},"date":{"type":"string"},"category":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]},"vendor":{"anyOf":[{"type":"string"},{"type":"null"}]},"paymentMethod":{"anyOf":[{"type":"string"},{"type":"null"}]},"paidAmount":{"type":"number"},"openBalance":{"type":"number"},"payments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"amount":{"type":"number"},"allocated":{"type":"number"},"paidAt":{"type":"string"},"method":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","amount","allocated","paidAt","method"],"additionalProperties":false}},"source":{"type":"string"},"status":{"type":"string"},"attachments":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"customers":{"type":"array","items":{"type":"object","properties":{"customerId":{"type":"string"},"customer":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]}},"required":["customerId","customer"],"additionalProperties":false}},"createdBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","description","amount","currency","date","category","vendor","paymentMethod","paidAmount","openBalance","payments","source","status","createdBy","createdAt","updatedAt"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount":{"type":"number"},"currency":{"type":"string"},"date":{"type":"string"},"category":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]},"vendor":{"anyOf":[{"type":"string"},{"type":"null"}]},"paymentMethod":{"anyOf":[{"type":"string"},{"type":"null"}]},"paidAmount":{"type":"number"},"openBalance":{"type":"number"},"payments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"amount":{"type":"number"},"allocated":{"type":"number"},"paidAt":{"type":"string"},"method":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","amount","allocated","paidAt","method"],"additionalProperties":false}},"source":{"type":"string"},"status":{"type":"string"},"attachments":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"customers":{"type":"array","items":{"type":"object","properties":{"customerId":{"type":"string"},"customer":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]}},"required":["customerId","customer"],"additionalProperties":false}},"createdBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","description","amount","currency","date","category","vendor","paymentMethod","paidAmount","openBalance","payments","source","status","createdBy","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["expenses:write"]}],"x-guliel-feature":"expenses","x-guliel-verb":"write","x-guliel-required-role":"CONTRIBUTOR","x-guliel-scope":"expenses:write"}},"/api/expenses/{id}":{"get":{"tags":["expenses"],"summary":"Get an expense","description":"Fetches a single expense by id. Returns 404 if the expense isn't in the caller's accessible organizations.\n\n**Scope:** `expenses:read`  \n**Endpoint:** `GET /api/expenses/{id}`","operationId":"expenses.get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"vendor":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount":{"type":"number"},"currency":{"type":"string"},"date":{"type":"string"},"status":{"type":"string"},"paymentMethod":{"anyOf":[{"type":"string"},{"type":"null"}]},"paidAmount":{"type":"number"},"openBalance":{"type":"number"},"payments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"amount":{"type":"number"},"allocated":{"type":"number"},"paidAt":{"type":"string"},"method":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","amount","allocated","paidAt","method"],"additionalProperties":false}},"taxAmount":{"anyOf":[{"type":"number"},{"type":"null"}]},"taxRate":{"anyOf":[{"type":"number"},{"type":"null"}]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"source":{"type":"string"},"emailMessageId":{"anyOf":[{"type":"string"},{"type":"null"}]},"category":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"color":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","color"],"additionalProperties":false},{"type":"null"}]},"customers":{"type":"array","items":{"type":"object","properties":{"customerId":{"type":"string"},"customer":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]}},"required":["customerId","customer"],"additionalProperties":false}},"attachments":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"createdBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false},{"type":"null"}]},"order":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"orderNumber":{"type":"string"},"status":{"type":"string"},"subtotal":{"type":"number"},"currency":{"type":"string"},"orderDate":{"type":"string"},"supplier":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"supplierOrganization":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]}},"required":["id","name","supplierOrganization"],"additionalProperties":false},{"type":"null"}]}},"required":["id","orderNumber","status","subtotal","currency","orderDate","supplier"],"additionalProperties":false},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","title","description","vendor","amount","currency","date","status","paymentMethod","paidAmount","openBalance","payments","taxAmount","taxRate","notes","source","emailMessageId","category","customers","attachments","createdBy","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["expenses:read"]}],"x-guliel-feature":"expenses","x-guliel-verb":"read","x-guliel-scope":"expenses:read"},"put":{"tags":["expenses"],"summary":"Update an expense","description":"Replaces an existing expense. All required fields must be supplied — omitted fields revert to their schema defaults.\n\n**Scope:** `expenses:write`  \n**Endpoint:** `PUT /api/expenses/{id}`","operationId":"expenses.update","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"vendor":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount":{"type":"number","exclusiveMinimum":0},"currency":{"type":"string","minLength":1},"date":{"type":"string"},"categoryId":{"anyOf":[{"type":"string"},{"type":"null"}]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"taxAmount":{"anyOf":[{"type":"number"},{"type":"null"}]},"taxRate":{"anyOf":[{"type":"number"},{"type":"null"}]},"paymentMethod":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"vendor":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount":{"type":"number"},"currency":{"type":"string"},"date":{"type":"string"},"status":{"type":"string"},"paymentMethod":{"anyOf":[{"type":"string"},{"type":"null"}]},"paidAmount":{"type":"number"},"openBalance":{"type":"number"},"payments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"amount":{"type":"number"},"allocated":{"type":"number"},"paidAt":{"type":"string"},"method":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","amount","allocated","paidAt","method"],"additionalProperties":false}},"taxAmount":{"anyOf":[{"type":"number"},{"type":"null"}]},"taxRate":{"anyOf":[{"type":"number"},{"type":"null"}]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"source":{"type":"string"},"emailMessageId":{"anyOf":[{"type":"string"},{"type":"null"}]},"category":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"color":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","color"],"additionalProperties":false},{"type":"null"}]},"customers":{"type":"array","items":{"type":"object","properties":{"customerId":{"type":"string"},"customer":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]}},"required":["customerId","customer"],"additionalProperties":false}},"attachments":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"createdBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false},{"type":"null"}]},"order":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"orderNumber":{"type":"string"},"status":{"type":"string"},"subtotal":{"type":"number"},"currency":{"type":"string"},"orderDate":{"type":"string"},"supplier":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"supplierOrganization":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]}},"required":["id","name","supplierOrganization"],"additionalProperties":false},{"type":"null"}]}},"required":["id","orderNumber","status","subtotal","currency","orderDate","supplier"],"additionalProperties":false},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","title","description","vendor","amount","currency","date","status","paymentMethod","paidAmount","openBalance","payments","taxAmount","taxRate","notes","source","emailMessageId","category","customers","attachments","createdBy","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["expenses:write"]}],"x-guliel-feature":"expenses","x-guliel-verb":"write","x-guliel-scope":"expenses:write"},"patch":{"tags":["expenses"],"summary":"Update an expense","description":"Updates an existing expense. Only the fields present in the request body are changed; omitted fields stay as-is.\n\n**Scope:** `expenses:write`  \n**Endpoint:** `PATCH /api/expenses/{id}`","operationId":"expenses.update","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"vendor":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount":{"type":"number","exclusiveMinimum":0},"currency":{"type":"string","minLength":1},"date":{"type":"string"},"categoryId":{"anyOf":[{"type":"string"},{"type":"null"}]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"taxAmount":{"anyOf":[{"type":"number"},{"type":"null"}]},"taxRate":{"anyOf":[{"type":"number"},{"type":"null"}]},"paymentMethod":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"vendor":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount":{"type":"number"},"currency":{"type":"string"},"date":{"type":"string"},"status":{"type":"string"},"paymentMethod":{"anyOf":[{"type":"string"},{"type":"null"}]},"paidAmount":{"type":"number"},"openBalance":{"type":"number"},"payments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"amount":{"type":"number"},"allocated":{"type":"number"},"paidAt":{"type":"string"},"method":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","amount","allocated","paidAt","method"],"additionalProperties":false}},"taxAmount":{"anyOf":[{"type":"number"},{"type":"null"}]},"taxRate":{"anyOf":[{"type":"number"},{"type":"null"}]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"source":{"type":"string"},"emailMessageId":{"anyOf":[{"type":"string"},{"type":"null"}]},"category":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"color":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","color"],"additionalProperties":false},{"type":"null"}]},"customers":{"type":"array","items":{"type":"object","properties":{"customerId":{"type":"string"},"customer":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]}},"required":["customerId","customer"],"additionalProperties":false}},"attachments":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"createdBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false},{"type":"null"}]},"order":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"orderNumber":{"type":"string"},"status":{"type":"string"},"subtotal":{"type":"number"},"currency":{"type":"string"},"orderDate":{"type":"string"},"supplier":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"supplierOrganization":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]}},"required":["id","name","supplierOrganization"],"additionalProperties":false},{"type":"null"}]}},"required":["id","orderNumber","status","subtotal","currency","orderDate","supplier"],"additionalProperties":false},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","title","description","vendor","amount","currency","date","status","paymentMethod","paidAmount","openBalance","payments","taxAmount","taxRate","notes","source","emailMessageId","category","customers","attachments","createdBy","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["expenses:write"]}],"x-guliel-feature":"expenses","x-guliel-verb":"write","x-guliel-scope":"expenses:write"},"delete":{"tags":["expenses"],"summary":"Delete an expense","description":"Deletes the expense. Some endpoints hard-delete the row, others soft-revoke (set `revokedAt`). Check the response shape.\n\n**Scope:** `expenses:write`  \n**Endpoint:** `DELETE /api/expenses/{id}`","operationId":"expenses.delete","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true}},"required":["success"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["expenses:write"]}],"x-guliel-feature":"expenses","x-guliel-verb":"write","x-guliel-scope":"expenses:write"}},"/api/expenses/{id}/customers":{"post":{"tags":["expenses"],"summary":"Attach customers to an expense","description":"Creates a new `customers` attached to the given expense.\n\n**Scope:** `expenses:write`  \n**Endpoint:** `POST /api/expenses/{id}/customers`","operationId":"expenses.customers","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"customerIds":{"minItems":1,"type":"array","items":{"type":"string","minLength":1}}},"required":["id","customerIds"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Updated expense with its full `customers` relation. See /api/expenses/[id] GET for the canonical shape."}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Updated expense with its full `customers` relation. See /api/expenses/[id] GET for the canonical shape."}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["expenses:write"]}],"x-guliel-feature":"expenses","x-guliel-verb":"write","x-guliel-scope":"expenses:write"},"delete":{"tags":["expenses"],"summary":"Detach customers from an expense","description":"Removes the association without deleting the underlying record.\n\n**Scope:** `expenses:write`  \n**Endpoint:** `DELETE /api/expenses/{id}/customers`","operationId":"expenses.customers","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."},{"name":"customerId","in":"query","required":true,"schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true}},"required":["success"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["expenses:write"]}],"x-guliel-feature":"expenses","x-guliel-verb":"write","x-guliel-scope":"expenses:write"}},"/api/expenses/{id}/payments":{"post":{"tags":["expenses"],"summary":"Attach payments to an expense","description":"Creates a new `payments` attached to the given expense.\n\n**Scope:** `expenses:write`  \n**Min role:** `CONTRIBUTOR` or higher  \n**Endpoint:** `POST /api/expenses/{id}/payments`","operationId":"expenses.payments","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"amount":{"type":"number","exclusiveMinimum":0},"paidAt":{"type":"string"},"method":{"anyOf":[{"type":"string"},{"type":"null"}]},"allowUnallocated":{"type":"boolean"}},"required":["id","amount","paidAt"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Updated expense row after settlement."}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Updated expense row after settlement."}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["expenses:write"]}],"x-guliel-feature":"expenses","x-guliel-verb":"write","x-guliel-required-role":"CONTRIBUTOR","x-guliel-scope":"expenses:write"}},"/api/expenses/{id}/status":{"patch":{"tags":["expenses"],"summary":"Update the expense status","description":"Mutates the state machine of the expense. Some transitions are restricted by role.\n\n**Scope:** `expenses:write`  \n**Endpoint:** `PATCH /api/expenses/{id}/status`","operationId":"expenses.status","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["DRAFT","PENDING_REVIEW","APPROVED","REJECTED"]},"reason":{"type":"string"}},"required":["id","status"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Updated expense row with category/customers/attachments joined. See /api/expenses/[id] GET for the canonical shape."}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["expenses:write"]}],"x-guliel-feature":"expenses","x-guliel-verb":"write","x-guliel-scope":"expenses:write"}},"/api/expenses/attachments/{id}":{"get":{"tags":["expenses"],"summary":"Attachment streaming for expenses","description":"Serves the raw attached file for an expense. The URL embeds a signed token; clients shouldn't construct it directly.\n\n**Scope:** `expenses:read`  \n**Endpoint:** `GET /api/expenses/attachments/{id}`","operationId":"expenses.get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["expenses:read"]}],"x-guliel-feature":"expenses","x-guliel-verb":"read","x-guliel-scope":"expenses:read"}},"/api/expenses/email-connect/gmail":{"post":{"tags":["integrations"],"summary":"Run email connect/gmail (expenses)","description":"Performs the `email-connect/gmail` operation for the expenses feature.\n\n**Scope:** `integrations:write`  \n**Min role:** `CONTRIBUTOR` or higher  \n**Auth sources:** `SESSION` only  \n**Endpoint:** `POST /api/expenses/email-connect/gmail`","operationId":"expenses.gmail","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"organizationId":{"type":"string","minLength":1},"name":{"default":"Gmail","type":"string","minLength":1}},"required":["organizationId","name"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"authorizeUrl":{"type":"string","description":"URL the browser opens to start the Gmail OAuth flow."},"state":{"type":"string","description":"Signed CSRF state token — round-tripped on the callback."}},"required":["authorizeUrl","state"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"authorizeUrl":{"type":"string","description":"URL the browser opens to start the Gmail OAuth flow."},"state":{"type":"string","description":"Signed CSRF state token — round-tripped on the callback."}},"required":["authorizeUrl","state"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["integrations:write"]}],"x-guliel-feature":"integrations","x-guliel-verb":"write","x-guliel-required-role":"CONTRIBUTOR","x-guliel-allowed-sources":["SESSION"],"x-guliel-scope":"integrations:write"}},"/api/expenses/email-connect/outlook":{"post":{"tags":["integrations"],"summary":"Run email connect/outlook (expenses)","description":"Performs the `email-connect/outlook` operation for the expenses feature.\n\n**Scope:** `integrations:write`  \n**Min role:** `CONTRIBUTOR` or higher  \n**Auth sources:** `SESSION` only  \n**Endpoint:** `POST /api/expenses/email-connect/outlook`","operationId":"expenses.outlook","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"organizationId":{"type":"string","minLength":1},"name":{"default":"Outlook","type":"string","minLength":1}},"required":["organizationId","name"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"authorizeUrl":{"type":"string","description":"URL the browser opens to start the Outlook OAuth flow."},"state":{"type":"string","description":"Signed CSRF state token — round-tripped on the callback."}},"required":["authorizeUrl","state"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"authorizeUrl":{"type":"string","description":"URL the browser opens to start the Outlook OAuth flow."},"state":{"type":"string","description":"Signed CSRF state token — round-tripped on the callback."}},"required":["authorizeUrl","state"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["integrations:write"]}],"x-guliel-feature":"integrations","x-guliel-verb":"write","x-guliel-required-role":"CONTRIBUTOR","x-guliel-allowed-sources":["SESSION"],"x-guliel-scope":"integrations:write"}},"/api/expenses/email-poll":{"post":{"tags":["expenses"],"summary":"Poll the expense inbox","description":"Pulls newly-arrived receipts from the connected mailbox and creates expenses for each one.\n\n**Scope:** `expenses:write`  \n**Min role:** `CONTRIBUTOR` or higher  \n**Endpoint:** `POST /api/expenses/email-poll`","operationId":"expenses.email_poll","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"organizationId":{"type":"string","minLength":1},"connectionId":{"type":"string","minLength":1},"dateFrom":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"dateTo":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["organizationId","connectionId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"runId":{"type":"string","description":"IngestionRun id — poll /api/expenses/fetch-logs to track it."},"status":{"type":"string","enum":["PENDING"],"description":"Always PENDING — queued for the worker; never executes in this request."}},"required":["runId","status"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"runId":{"type":"string","description":"IngestionRun id — poll /api/expenses/fetch-logs to track it."},"status":{"type":"string","enum":["PENDING"],"description":"Always PENDING — queued for the worker; never executes in this request."}},"required":["runId","status"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["expenses:write"]}],"x-guliel-feature":"expenses","x-guliel-verb":"write","x-guliel-required-role":"CONTRIBUTOR","x-guliel-scope":"expenses:write"}},"/api/expenses/email-settings":{"get":{"tags":["integrations"],"summary":"Get email settings (expenses)","description":"Returns the `email-settings` data for the expenses feature.\n\n**Scope:** `integrations:read`  \n**Endpoint:** `GET /api/expenses/email-settings`","operationId":"expenses.email_settings","parameters":[{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}},{"name":"id","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","anyOf":[{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"name":{"type":"string"},"provider":{"type":"string"},"enabled":{"type":"boolean"},"tokenExpiresAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"host":{"anyOf":[{"type":"string"},{"type":"null"}]},"port":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"useTls":{"type":"boolean"},"username":{"anyOf":[{"type":"string"},{"type":"null"}]},"hasPassword":{"type":"boolean","description":"Whether an IMAP/POP3 password is stored. The password itself is never returned."},"folderOrLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"subjectFilter":{"anyOf":[{"type":"string"},{"type":"null"}]},"senderWhitelist":{"type":"array","items":{"type":"string"}},"autoPollEnabled":{"type":"boolean"},"pollIntervalDays":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"lastPolledAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","name","provider","enabled","tokenExpiresAt","host","port","useTls","username","hasPassword","folderOrLabel","subjectFilter","senderWhitelist","autoPollEnabled","pollIntervalDays","lastPolledAt","createdAt","updatedAt"],"additionalProperties":false},{"type":"null"}]},{"type":"object","properties":{"connections":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"name":{"type":"string"},"provider":{"type":"string"},"enabled":{"type":"boolean"},"tokenExpiresAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"host":{"anyOf":[{"type":"string"},{"type":"null"}]},"port":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"useTls":{"type":"boolean"},"username":{"anyOf":[{"type":"string"},{"type":"null"}]},"hasPassword":{"type":"boolean","description":"Whether an IMAP/POP3 password is stored. The password itself is never returned."},"folderOrLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"subjectFilter":{"anyOf":[{"type":"string"},{"type":"null"}]},"senderWhitelist":{"type":"array","items":{"type":"string"}},"autoPollEnabled":{"type":"boolean"},"pollIntervalDays":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"lastPolledAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","name","provider","enabled","tokenExpiresAt","host","port","useTls","username","hasPassword","folderOrLabel","subjectFilter","senderWhitelist","autoPollEnabled","pollIntervalDays","lastPolledAt","createdAt","updatedAt"],"additionalProperties":false}}},"required":["connections"],"additionalProperties":false}],"description":"Returns a single connection (when `id` is given) or `{ connections: [...] }` for the list view. Secrets are never included; `hasPassword` reports whether a credential is on file."}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["integrations:read"]}],"x-guliel-feature":"integrations","x-guliel-verb":"read","x-guliel-scope":"integrations:read"},"post":{"tags":["integrations"],"summary":"Run email settings (expenses)","description":"Performs the `email-settings` operation for the expenses feature.\n\n**Scope:** `integrations:write`  \n**Min role:** `MANAGER` or higher  \n**Endpoint:** `POST /api/expenses/email-settings`","operationId":"expenses.email_settings","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"organizationId":{"type":"string","minLength":1},"name":{"type":"string","minLength":1},"provider":{"type":"string","enum":["GMAIL","OUTLOOK","IMAP","POP3"]},"enabled":{"type":"boolean"},"host":{"anyOf":[{"type":"string"},{"type":"null"}]},"port":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"useTls":{"type":"boolean"},"username":{"anyOf":[{"type":"string"},{"type":"null"}]},"password":{"anyOf":[{"type":"string"},{"type":"null"}]},"folderOrLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"subjectFilter":{"anyOf":[{"type":"string"},{"type":"null"}]},"senderWhitelist":{"type":"array","items":{"type":"string"}},"autoPollEnabled":{"type":"boolean"},"pollIntervalDays":{"type":"integer","minimum":1,"maximum":365}},"required":["organizationId","name","provider"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"name":{"type":"string"},"provider":{"type":"string"},"enabled":{"type":"boolean"},"tokenExpiresAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"host":{"anyOf":[{"type":"string"},{"type":"null"}]},"port":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"useTls":{"type":"boolean"},"username":{"anyOf":[{"type":"string"},{"type":"null"}]},"hasPassword":{"type":"boolean","description":"Whether an IMAP/POP3 password is stored. The password itself is never returned."},"folderOrLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"subjectFilter":{"anyOf":[{"type":"string"},{"type":"null"}]},"senderWhitelist":{"type":"array","items":{"type":"string"}},"autoPollEnabled":{"type":"boolean"},"pollIntervalDays":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"lastPolledAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","name","provider","enabled","tokenExpiresAt","host","port","useTls","username","hasPassword","folderOrLabel","subjectFilter","senderWhitelist","autoPollEnabled","pollIntervalDays","lastPolledAt","createdAt","updatedAt"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"name":{"type":"string"},"provider":{"type":"string"},"enabled":{"type":"boolean"},"tokenExpiresAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"host":{"anyOf":[{"type":"string"},{"type":"null"}]},"port":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"useTls":{"type":"boolean"},"username":{"anyOf":[{"type":"string"},{"type":"null"}]},"hasPassword":{"type":"boolean","description":"Whether an IMAP/POP3 password is stored. The password itself is never returned."},"folderOrLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"subjectFilter":{"anyOf":[{"type":"string"},{"type":"null"}]},"senderWhitelist":{"type":"array","items":{"type":"string"}},"autoPollEnabled":{"type":"boolean"},"pollIntervalDays":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"lastPolledAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","name","provider","enabled","tokenExpiresAt","host","port","useTls","username","hasPassword","folderOrLabel","subjectFilter","senderWhitelist","autoPollEnabled","pollIntervalDays","lastPolledAt","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["integrations:write"]}],"x-guliel-feature":"integrations","x-guliel-verb":"write","x-guliel-required-role":"MANAGER","x-guliel-scope":"integrations:write"},"put":{"tags":["integrations"],"summary":"Update email settings (expenses)","description":"Mutates the `email-settings` configuration for the expenses feature.\n\n**Scope:** `integrations:write`  \n**Min role:** `MANAGER` or higher  \n**Endpoint:** `PUT /api/expenses/email-settings`","operationId":"expenses.email_settings","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","minLength":1},"organizationId":{"type":"string","minLength":1},"name":{"type":"string","minLength":1},"enabled":{"type":"boolean"},"host":{"anyOf":[{"type":"string"},{"type":"null"}]},"port":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"useTls":{"type":"boolean"},"username":{"anyOf":[{"type":"string"},{"type":"null"}]},"password":{"anyOf":[{"type":"string"},{"type":"null"}]},"folderOrLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"subjectFilter":{"anyOf":[{"type":"string"},{"type":"null"}]},"senderWhitelist":{"type":"array","items":{"type":"string"}},"autoPollEnabled":{"type":"boolean"},"pollIntervalDays":{"type":"integer","minimum":1,"maximum":365},"provider":{"type":"string","enum":["GMAIL","OUTLOOK","IMAP","POP3"]}},"required":["id","organizationId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"name":{"type":"string"},"provider":{"type":"string"},"enabled":{"type":"boolean"},"tokenExpiresAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"host":{"anyOf":[{"type":"string"},{"type":"null"}]},"port":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"useTls":{"type":"boolean"},"username":{"anyOf":[{"type":"string"},{"type":"null"}]},"hasPassword":{"type":"boolean","description":"Whether an IMAP/POP3 password is stored. The password itself is never returned."},"folderOrLabel":{"anyOf":[{"type":"string"},{"type":"null"}]},"subjectFilter":{"anyOf":[{"type":"string"},{"type":"null"}]},"senderWhitelist":{"type":"array","items":{"type":"string"}},"autoPollEnabled":{"type":"boolean"},"pollIntervalDays":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"lastPolledAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","name","provider","enabled","tokenExpiresAt","host","port","useTls","username","hasPassword","folderOrLabel","subjectFilter","senderWhitelist","autoPollEnabled","pollIntervalDays","lastPolledAt","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["integrations:write"]}],"x-guliel-feature":"integrations","x-guliel-verb":"write","x-guliel-required-role":"MANAGER","x-guliel-scope":"integrations:write"},"delete":{"tags":["integrations"],"summary":"Remove email settings (expenses)","description":"Removes the `email-settings` configuration for the expenses feature.\n\n**Scope:** `integrations:write`  \n**Min role:** `MANAGER` or higher  \n**Endpoint:** `DELETE /api/expenses/email-settings`","operationId":"expenses.email_settings","parameters":[{"name":"id","in":"query","required":true,"schema":{"type":"string","minLength":1}},{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true}},"required":["success"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["integrations:write"]}],"x-guliel-feature":"integrations","x-guliel-verb":"write","x-guliel-required-role":"MANAGER","x-guliel-scope":"integrations:write"}},"/api/expenses/email-settings/{id}/auto-scan":{"get":{"tags":["integrations"],"summary":"List email settings/auto scan for an expense","description":"Returns every `email-settings/auto-scan` row associated with the given expense.\n\n**Scope:** `integrations:read`  \n**Min role:** `VIEWER` or higher  \n**Endpoint:** `GET /api/expenses/email-settings/{id}/auto-scan`","operationId":"expenses.auto_scan","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."},{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"connectionId":{"type":"string"},"automationId":{"anyOf":[{"type":"string"},{"type":"null"}]},"cadence":{"type":"string","enum":["OFF","DAILY","WEEKLY","MONTHLY"]},"automationStatus":{"anyOf":[{"type":"string","enum":["ENABLED","DISABLED","PAUSED_NO_ACCESS"]},{"type":"null"}]}},"required":["connectionId","automationId","cadence","automationStatus"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["integrations:read"]}],"x-guliel-feature":"integrations","x-guliel-verb":"read","x-guliel-required-role":"VIEWER","x-guliel-scope":"integrations:read"},"post":{"tags":["integrations"],"summary":"Set a connection's scheduled auto-scan","description":"Creates a new `email-settings/auto-scan` attached to the given expense.\n\n**Scope:** `integrations:write`  \n**Min role:** `CONTRIBUTOR` or higher  \n**Endpoint:** `POST /api/expenses/email-settings/{id}/auto-scan`","operationId":"expenses.auto_scan","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"organizationId":{"type":"string","minLength":1},"id":{"type":"string","minLength":1},"cadence":{"type":"string","enum":["OFF","DAILY","WEEKLY","MONTHLY"]}},"required":["organizationId","id","cadence"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"connectionId":{"type":"string"},"automationId":{"anyOf":[{"type":"string"},{"type":"null"}]},"cadence":{"type":"string","enum":["OFF","DAILY","WEEKLY","MONTHLY"]},"automationStatus":{"anyOf":[{"type":"string","enum":["ENABLED","DISABLED","PAUSED_NO_ACCESS"]},{"type":"null"}]}},"required":["connectionId","automationId","cadence","automationStatus"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"connectionId":{"type":"string"},"automationId":{"anyOf":[{"type":"string"},{"type":"null"}]},"cadence":{"type":"string","enum":["OFF","DAILY","WEEKLY","MONTHLY"]},"automationStatus":{"anyOf":[{"type":"string","enum":["ENABLED","DISABLED","PAUSED_NO_ACCESS"]},{"type":"null"}]}},"required":["connectionId","automationId","cadence","automationStatus"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["integrations:write"]}],"x-guliel-feature":"integrations","x-guliel-verb":"write","x-guliel-required-role":"CONTRIBUTOR","x-guliel-scope":"integrations:write"},"delete":{"tags":["integrations"],"summary":"Detach email settings/auto scan from an expense","description":"Removes the association without deleting the underlying record.\n\n**Scope:** `integrations:write`  \n**Min role:** `CONTRIBUTOR` or higher  \n**Endpoint:** `DELETE /api/expenses/email-settings/{id}/auto-scan`","operationId":"expenses.auto_scan","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."},{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"connectionId":{"type":"string"},"automationId":{"anyOf":[{"type":"string"},{"type":"null"}]},"cadence":{"type":"string","enum":["OFF","DAILY","WEEKLY","MONTHLY"]},"automationStatus":{"anyOf":[{"type":"string","enum":["ENABLED","DISABLED","PAUSED_NO_ACCESS"]},{"type":"null"}]}},"required":["connectionId","automationId","cadence","automationStatus"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["integrations:write"]}],"x-guliel-feature":"integrations","x-guliel-verb":"write","x-guliel-required-role":"CONTRIBUTOR","x-guliel-scope":"integrations:write"}},"/api/expenses/export/csv":{"get":{"tags":["expenses"],"summary":"Export expenses as CSV","description":"Streams the caller's expenses as a CSV file. Filter parameters scope the export the same way the list endpoint does.\n\n**Scope:** `expenses:read`  \n**Endpoint:** `GET /api/expenses/export/csv`","operationId":"expenses.csv","parameters":[{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"source","in":"query","required":false,"schema":{"type":"string"}},{"name":"categoryId","in":"query","required":false,"schema":{"type":"string"}},{"name":"dateFrom","in":"query","required":false,"schema":{"type":"string"}},{"name":"dateTo","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["expenses:read"]}],"x-guliel-feature":"expenses","x-guliel-verb":"read","x-guliel-scope":"expenses:read"}},"/api/expenses/export/manifest":{"get":{"tags":["expenses"],"summary":"Export expenses as MANIFEST","description":"Streams the caller's expenses as a MANIFEST file. Filter parameters scope the export the same way the list endpoint does.\n\n**Scope:** `expenses:read`  \n**Endpoint:** `GET /api/expenses/export/manifest`","operationId":"expenses.manifest","parameters":[{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}},{"name":"ids","in":"query","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"source","in":"query","required":false,"schema":{"type":"string"}},{"name":"categoryId","in":"query","required":false,"schema":{"type":"string"}},{"name":"dateFrom","in":"query","required":false,"schema":{"type":"string"}},{"name":"dateTo","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"organization":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},"generatedAt":{"type":"string"},"expenses":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"date":{"type":"string"},"vendor":{"anyOf":[{"type":"string"},{"type":"null"}]},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"category":{"anyOf":[{"type":"string"},{"type":"null"}]},"amount":{"type":"string","description":"Decimal serialized as string to avoid float drift."},"currency":{"type":"string"},"taxAmount":{"anyOf":[{"type":"string"},{"type":"null"}]},"taxRate":{"anyOf":[{"type":"string"},{"type":"null"}]},"paymentMethod":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string"},"source":{"type":"string"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"attachments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"fileName":{"type":"string"},"fileType":{"anyOf":[{"type":"string"},{"type":"null"}]},"fileSize":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}},"required":["id","fileName","fileType","fileSize"],"additionalProperties":false}},"createdBy":{"anyOf":[{"type":"object","properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["name","email"],"additionalProperties":false},{"type":"null"}]}},"required":["id","date","vendor","title","category","amount","currency","taxAmount","taxRate","paymentMethod","status"],"additionalProperties":false}}},"required":["organization","generatedAt","expenses"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["expenses:read"]}],"x-guliel-feature":"expenses","x-guliel-verb":"read","x-guliel-scope":"expenses:read"}},"/api/expenses/fetch-logs":{"get":{"tags":["integrations"],"summary":"Get fetch logs (expenses)","description":"Returns the `fetch-logs` data for the expenses feature.\n\n**Scope:** `integrations:read`  \n**Endpoint:** `GET /api/expenses/fetch-logs`","operationId":"expenses.fetch_logs","parameters":[{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}},{"name":"connectionId","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"runs":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"connectionId":{"type":"string"},"status":{"type":"string","enum":["PENDING","RUNNING","DONE","ERROR","MANUAL_STOP"]},"dateFrom":{"type":"string"},"dateTo":{"type":"string"},"emailsScanned":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"emailsDetected":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"expensesCreated":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"errorMessage":{"anyOf":[{"type":"string"},{"type":"null"}]},"startedAt":{"type":"string"},"completedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"claimedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When a worker claimed the run; null on a legacy sync run"},"lastProgressAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Heartbeat — bumped per processed message"},"messages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"messageId":{"type":"string"},"subject":{"anyOf":[{"type":"string"},{"type":"null"}]},"outcome":{"type":"string","enum":["CREATED","DUPLICATE","SKIPPED_NOT_EXPENSE","DROPPED_NO_DATA","FAILED"]},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Short human-readable disposition reason"},"processedAt":{"type":"string"}},"required":["id","messageId","subject","outcome","reason","processedAt"],"additionalProperties":false}}},"required":["id","connectionId","status","dateFrom","dateTo","emailsScanned","emailsDetected","expensesCreated","errorMessage","startedAt","completedAt","claimedAt","lastProgressAt","messages"],"additionalProperties":false}}},"required":["runs"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["integrations:read"]}],"x-guliel-feature":"integrations","x-guliel-verb":"read","x-guliel-scope":"integrations:read"}},"/api/expenses/fetch-logs/{id}/stop":{"post":{"tags":["integrations"],"summary":"Attach fetch logs/stop to an expense","description":"Creates a new `fetch-logs/stop` attached to the given expense.\n\n**Scope:** `integrations:write`  \n**Endpoint:** `POST /api/expenses/fetch-logs/{id}/stop`","operationId":"expenses.stop","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true}},"required":["success"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true}},"required":["success"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["integrations:write"]}],"x-guliel-feature":"integrations","x-guliel-verb":"write","x-guliel-scope":"integrations:write"}},"/api/expenses/scan":{"post":{"tags":["expenses"],"summary":"Run scan (expenses)","description":"Performs the `scan` operation for the expenses feature.\n\n**Scope:** `expenses:write`  \n**Endpoint:** `POST /api/expenses/scan`","operationId":"expenses.scan","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"attachmentId":{"type":"string","minLength":1}},"required":["attachmentId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"expenseId":{"type":"string","description":"Id of the scanned expense document."},"mergedIntoOrder":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"orderNumber":{"type":"string"}},"required":["id","orderNumber"],"additionalProperties":false},{"type":"null"}],"description":"When the scan matched an open purchase order, the order it was linked to — the scanned document joins that order's document chain."},"orderTransition":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"extractedData":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Raw OCR / AI extraction output (vendor, line items, totals, etc.). Empty object when the scan failed."},"vendorMatch":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"providerId":{"type":"string"},"processingTimeMs":{"type":"number"},"scanStatus":{"type":"string","enum":["COMPLETED","FAILED"],"description":"Whether the scan produced usable data and fields were applied (COMPLETED) or not (FAILED — empty/unreadable result, unsupported type, provider error, or duplicate)."},"scanError":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Human-readable reason when scanStatus is FAILED; null on success."},"duplicateOfId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the scan was rejected as a duplicate (same org + externalDocId + vendor), the id of the existing document it duplicates; null otherwise."}},"required":["expenseId","mergedIntoOrder","extractedData","providerId","processingTimeMs","scanStatus","scanError","duplicateOfId"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"expenseId":{"type":"string","description":"Id of the scanned expense document."},"mergedIntoOrder":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"orderNumber":{"type":"string"}},"required":["id","orderNumber"],"additionalProperties":false},{"type":"null"}],"description":"When the scan matched an open purchase order, the order it was linked to — the scanned document joins that order's document chain."},"orderTransition":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"extractedData":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Raw OCR / AI extraction output (vendor, line items, totals, etc.). Empty object when the scan failed."},"vendorMatch":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"providerId":{"type":"string"},"processingTimeMs":{"type":"number"},"scanStatus":{"type":"string","enum":["COMPLETED","FAILED"],"description":"Whether the scan produced usable data and fields were applied (COMPLETED) or not (FAILED — empty/unreadable result, unsupported type, provider error, or duplicate)."},"scanError":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Human-readable reason when scanStatus is FAILED; null on success."},"duplicateOfId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"When the scan was rejected as a duplicate (same org + externalDocId + vendor), the id of the existing document it duplicates; null otherwise."}},"required":["expenseId","mergedIntoOrder","extractedData","providerId","processingTimeMs","scanStatus","scanError","duplicateOfId"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["expenses:write"]}],"x-guliel-feature":"expenses","x-guliel-verb":"write","x-guliel-scope":"expenses:write"}},"/api/expenses/upload":{"post":{"tags":["expenses"],"summary":"Run upload (expenses)","description":"Performs the `upload` operation for the expenses feature.\n\n**Scope:** `expenses:write`  \n**Endpoint:** `POST /api/expenses/upload`","operationId":"expenses.upload","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{},"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"expenseId":{"type":"string"},"fileName":{"type":"string"},"fileType":{"anyOf":[{"type":"string"},{"type":"null"}]},"fileSize":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"storageUrl":{"type":"string"}},"required":["id","expenseId","fileName","fileType","fileSize","storageUrl"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"expenseId":{"type":"string"},"fileName":{"type":"string"},"fileType":{"anyOf":[{"type":"string"},{"type":"null"}]},"fileSize":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"storageUrl":{"type":"string"}},"required":["id","expenseId","fileName","fileType","fileSize","storageUrl"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["expenses:write"]}],"x-guliel-feature":"expenses","x-guliel-verb":"write","x-guliel-scope":"expenses:write"}},"/api/expenses/usage":{"get":{"tags":["expenses"],"summary":"expense usage history","description":"Returns the caller's recent request log for the expense (last 7 days by default).\n\n**Scope:** `expenses:read`  \n**Endpoint:** `GET /api/expenses/usage`","operationId":"expenses.usage","parameters":[{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"used":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Scans consumed in the current billing period."},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Allowed scans for the org's plan."},"period":{"type":"string","description":"Billing period the counters cover, e.g. \"2026-05\"."}},"required":["used","limit","period"],"additionalProperties":false,"description":"Snapshot of the org's monthly OCR/scan quota usage."}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["expenses:read"]}],"x-guliel-feature":"expenses","x-guliel-verb":"read","x-guliel-scope":"expenses:read"}},"/api/invitations":{"get":{"tags":["users"],"summary":"List invitations","description":"Lists invitations the caller can see. Results are filtered by the caller's accessible organizations; many routes paginate via `page` and `limit`.\n\n**Scope:** `users:read`  \n**Min role:** `MANAGER` or higher  \n**Endpoint:** `GET /api/invitations`","operationId":"invitations.invitations","parameters":[{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"invitations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"email":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"role":{"type":"string"},"token":{"type":"string","description":"Pre-signed acceptance token — never expose to the invitee in the UI directly; deliver via email link only."},"status":{"type":"string","description":"PENDING | ACCEPTED | DECLINED | EXPIRED"},"invitedById":{"type":"string"},"acceptedById":{"anyOf":[{"type":"string"},{"type":"null"}]},"expiresAt":{"type":"string"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"invitedBy":{"anyOf":[{"type":"object","properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["name","email"],"additionalProperties":false},{"type":"null"}]},"acceptedBy":{"anyOf":[{"type":"object","properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["name","email"],"additionalProperties":false},{"type":"null"}]},"organization":{"anyOf":[{"type":"object","properties":{"name":{"type":"string"}},"required":["name"],"additionalProperties":false},{"type":"null"}]}},"required":["id","organizationId","email","name","role","token","status","invitedById","acceptedById","expiresAt","createdAt","updatedAt"],"additionalProperties":false}}},"required":["invitations"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:read"]}],"x-guliel-feature":"users","x-guliel-verb":"read","x-guliel-required-role":"MANAGER","x-guliel-scope":"users:read"},"post":{"tags":["users"],"summary":"Create an invitation","description":"Creates a new invitation in the target organization. Returns the created record on success.\n\n**Scope:** `users:write`  \n**Min role:** `MANAGER` or higher  \n**Endpoint:** `POST /api/invitations`","operationId":"invitations.invitations","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/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"},"role":{"type":"string","enum":["MANAGER","CONTRIBUTOR","VIEWER"]},"organizationId":{"type":"string"}},"required":["email","role","organizationId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"email":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"role":{"type":"string"},"token":{"type":"string","description":"Pre-signed acceptance token — never expose to the invitee in the UI directly; deliver via email link only."},"status":{"type":"string","description":"PENDING | ACCEPTED | DECLINED | EXPIRED"},"invitedById":{"type":"string"},"acceptedById":{"anyOf":[{"type":"string"},{"type":"null"}]},"expiresAt":{"type":"string"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"invitedBy":{"anyOf":[{"type":"object","properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["name","email"],"additionalProperties":false},{"type":"null"}]},"acceptedBy":{"anyOf":[{"type":"object","properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["name","email"],"additionalProperties":false},{"type":"null"}]},"organization":{"anyOf":[{"type":"object","properties":{"name":{"type":"string"}},"required":["name"],"additionalProperties":false},{"type":"null"}]}},"required":["id","organizationId","email","name","role","token","status","invitedById","acceptedById","expiresAt","createdAt","updatedAt"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"email":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"role":{"type":"string"},"token":{"type":"string","description":"Pre-signed acceptance token — never expose to the invitee in the UI directly; deliver via email link only."},"status":{"type":"string","description":"PENDING | ACCEPTED | DECLINED | EXPIRED"},"invitedById":{"type":"string"},"acceptedById":{"anyOf":[{"type":"string"},{"type":"null"}]},"expiresAt":{"type":"string"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"invitedBy":{"anyOf":[{"type":"object","properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["name","email"],"additionalProperties":false},{"type":"null"}]},"acceptedBy":{"anyOf":[{"type":"object","properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["name","email"],"additionalProperties":false},{"type":"null"}]},"organization":{"anyOf":[{"type":"object","properties":{"name":{"type":"string"}},"required":["name"],"additionalProperties":false},{"type":"null"}]}},"required":["id","organizationId","email","name","role","token","status","invitedById","acceptedById","expiresAt","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:write"]}],"x-guliel-feature":"users","x-guliel-verb":"write","x-guliel-required-role":"MANAGER","x-guliel-scope":"users:write"}},"/api/invitations/{id}":{"delete":{"tags":["users"],"summary":"Delete an invitation","description":"Deletes the invitation. Some endpoints hard-delete the row, others soft-revoke (set `revokedAt`). Check the response shape.\n\n**Scope:** `users:write`  \n**Endpoint:** `DELETE /api/invitations/{id}`","operationId":"invitations.delete","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true}},"required":["success"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:write"]}],"x-guliel-feature":"users","x-guliel-verb":"write","x-guliel-scope":"users:write"}},"/api/invitations/{id}/resend":{"post":{"tags":["users"],"summary":"Attach resend to an invitation","description":"Creates a new `resend` attached to the given invitation.\n\n**Scope:** `users:write`  \n**Endpoint:** `POST /api/invitations/{id}/resend`","operationId":"invitations.resend","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Updated invitation row — see /api/invitations GET for the canonical shape."}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Updated invitation row — see /api/invitations GET for the canonical shape."}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:write"]}],"x-guliel-feature":"users","x-guliel-verb":"write","x-guliel-scope":"users:write"}},"/api/items":{"get":{"tags":["logistics"],"summary":"List items","description":"Lists items the caller can see. Results are filtered by the caller's accessible organizations; many routes paginate via `page` and `limit`.\n\n**Scope:** `logistics:read`  \n**Endpoint:** `GET /api/items`","operationId":"items.items","parameters":[{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}},{"name":"page","in":"query","required":true,"schema":{"default":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"name":"limit","in":"query","required":true,"schema":{"default":25,"type":"integer","minimum":1,"maximum":100}},{"name":"search","in":"query","required":true,"schema":{"default":"","type":"string"}},{"name":"isActive","in":"query","required":false,"schema":{"type":"string"}},{"name":"hasStock","in":"query","required":false,"schema":{"type":"string"}},{"name":"currency","in":"query","required":false,"schema":{"type":"string"}},{"name":"sortBy","in":"query","required":true,"schema":{"default":"name","type":"string","enum":["name","sku","unitPrice","quantity","createdAt","updatedAt"]}},{"name":"sortOrder","in":"query","required":true,"schema":{"default":"asc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"sku":{"anyOf":[{"type":"string"},{"type":"null"}]},"unitPrice":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Unit price in `currency`; null when the item has no default price."},"currency":{"anyOf":[{"type":"string"},{"type":"null"}]},"quantity":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Stock on hand. Null means the item is not stock-tracked."},"lowStockThreshold":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"isActive":{"type":"boolean"},"availableForExternalOrder":{"type":"boolean"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","name","description","sku","unitPrice","currency","quantity","lowStockThreshold","isActive","availableForExternalOrder","createdAt","updatedAt"],"additionalProperties":false}},"lowStockCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many active stock-tracked items are at or below their lowStockThreshold."},"pagination":{"type":"object","properties":{"page":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"totalPages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["page","limit","total","totalPages"],"additionalProperties":false}},"required":["items","lowStockCount","pagination"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["logistics:read"]}],"x-guliel-feature":"logistics","x-guliel-verb":"read","x-guliel-scope":"logistics:read"},"post":{"tags":["logistics"],"summary":"Create an item","description":"Creates a new item in the target organization. Returns the created record on success.\n\n**Scope:** `logistics:write`  \n**Min role:** `CONTRIBUTOR` or higher  \n**Endpoint:** `POST /api/items`","operationId":"items.items","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"organizationId":{"type":"string","minLength":1},"name":{"type":"string","minLength":1},"description":{"type":"string"},"sku":{"type":"string"},"unitPrice":{"anyOf":[{"type":"number","minimum":0},{"type":"null"}]},"currency":{"default":"USD","type":"string"},"quantity":{"anyOf":[{"type":"number","minimum":0},{"type":"null"}]},"lowStockThreshold":{"default":5,"type":"integer","minimum":0,"maximum":9007199254740991},"availableForExternalOrder":{"default":false,"type":"boolean"}},"required":["organizationId","name","currency","lowStockThreshold","availableForExternalOrder"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"sku":{"anyOf":[{"type":"string"},{"type":"null"}]},"unitPrice":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Unit price in `currency`; null when the item has no default price."},"currency":{"anyOf":[{"type":"string"},{"type":"null"}]},"quantity":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Stock on hand. Null means the item is not stock-tracked."},"lowStockThreshold":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"isActive":{"type":"boolean"},"availableForExternalOrder":{"type":"boolean"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","name","description","sku","unitPrice","currency","quantity","lowStockThreshold","isActive","availableForExternalOrder","createdAt","updatedAt"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"sku":{"anyOf":[{"type":"string"},{"type":"null"}]},"unitPrice":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Unit price in `currency`; null when the item has no default price."},"currency":{"anyOf":[{"type":"string"},{"type":"null"}]},"quantity":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Stock on hand. Null means the item is not stock-tracked."},"lowStockThreshold":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"isActive":{"type":"boolean"},"availableForExternalOrder":{"type":"boolean"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","name","description","sku","unitPrice","currency","quantity","lowStockThreshold","isActive","availableForExternalOrder","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["logistics:write"]}],"x-guliel-feature":"logistics","x-guliel-verb":"write","x-guliel-required-role":"CONTRIBUTOR","x-guliel-scope":"logistics:write"}},"/api/items/{id}":{"get":{"tags":["logistics"],"summary":"Get an item","description":"Fetches a single item by id. Returns 404 if the item isn't in the caller's accessible organizations.\n\n**Scope:** `logistics:read`  \n**Endpoint:** `GET /api/items/{id}`","operationId":"items.get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"sku":{"anyOf":[{"type":"string"},{"type":"null"}]},"unitPrice":{"anyOf":[{"type":"number"},{"type":"null"}]},"currency":{"anyOf":[{"type":"string"},{"type":"null"}]},"quantity":{"anyOf":[{"type":"number"},{"type":"null"}]},"lowStockThreshold":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"isActive":{"type":"boolean"},"availableForExternalOrder":{"type":"boolean"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","name","description","sku","unitPrice","currency","quantity","lowStockThreshold","isActive","availableForExternalOrder","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["logistics:read"]}],"x-guliel-feature":"logistics","x-guliel-verb":"read","x-guliel-scope":"logistics:read"},"put":{"tags":["logistics"],"summary":"Update an item","description":"Replaces an existing item. All required fields must be supplied — omitted fields revert to their schema defaults.\n\n**Scope:** `logistics:write`  \n**Endpoint:** `PUT /api/items/{id}`","operationId":"items.update","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","minLength":1},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"sku":{"anyOf":[{"type":"string"},{"type":"null"}]},"unitPrice":{"anyOf":[{"type":"number","minimum":0},{"type":"null"}]},"currency":{"type":"string"},"lowStockThreshold":{"type":"integer","minimum":0,"maximum":9007199254740991},"isActive":{"type":"boolean"},"availableForExternalOrder":{"type":"boolean"}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"sku":{"anyOf":[{"type":"string"},{"type":"null"}]},"unitPrice":{"anyOf":[{"type":"number"},{"type":"null"}]},"currency":{"anyOf":[{"type":"string"},{"type":"null"}]},"quantity":{"anyOf":[{"type":"number"},{"type":"null"}]},"lowStockThreshold":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"isActive":{"type":"boolean"},"availableForExternalOrder":{"type":"boolean"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","name","description","sku","unitPrice","currency","quantity","lowStockThreshold","isActive","availableForExternalOrder","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["logistics:write"]}],"x-guliel-feature":"logistics","x-guliel-verb":"write","x-guliel-scope":"logistics:write"},"patch":{"tags":["logistics"],"summary":"Update an item","description":"Updates an existing item. Only the fields present in the request body are changed; omitted fields stay as-is.\n\n**Scope:** `logistics:write`  \n**Endpoint:** `PATCH /api/items/{id}`","operationId":"items.update","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","minLength":1},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"sku":{"anyOf":[{"type":"string"},{"type":"null"}]},"unitPrice":{"anyOf":[{"type":"number","minimum":0},{"type":"null"}]},"currency":{"type":"string"},"lowStockThreshold":{"type":"integer","minimum":0,"maximum":9007199254740991},"isActive":{"type":"boolean"},"availableForExternalOrder":{"type":"boolean"}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"sku":{"anyOf":[{"type":"string"},{"type":"null"}]},"unitPrice":{"anyOf":[{"type":"number"},{"type":"null"}]},"currency":{"anyOf":[{"type":"string"},{"type":"null"}]},"quantity":{"anyOf":[{"type":"number"},{"type":"null"}]},"lowStockThreshold":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"isActive":{"type":"boolean"},"availableForExternalOrder":{"type":"boolean"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","name","description","sku","unitPrice","currency","quantity","lowStockThreshold","isActive","availableForExternalOrder","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["logistics:write"]}],"x-guliel-feature":"logistics","x-guliel-verb":"write","x-guliel-scope":"logistics:write"},"delete":{"tags":["logistics"],"summary":"Delete an item","description":"Deletes the item. Some endpoints hard-delete the row, others soft-revoke (set `revokedAt`). Check the response shape.\n\n**Scope:** `logistics:write`  \n**Endpoint:** `DELETE /api/items/{id}`","operationId":"items.delete","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true}},"required":["success"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["logistics:write"]}],"x-guliel-feature":"logistics","x-guliel-verb":"write","x-guliel-scope":"logistics:write"}},"/api/items/{id}/movements":{"get":{"tags":["logistics"],"summary":"List movements for an item","description":"Returns every `movements` row associated with the given item.\n\n**Scope:** `logistics:read`  \n**Endpoint:** `GET /api/items/{id}/movements`","operationId":"items.movements","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."},{"name":"page","in":"query","required":true,"schema":{"default":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"name":"limit","in":"query","required":true,"schema":{"default":20,"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"movements":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"itemId":{"type":"string"},"type":{"type":"string","description":"INVOICE_DEDUCT | INVOICE_RESTORE | MANUAL_ADD | MANUAL_SET | RECEIPT | etc."},"delta":{"type":"number"},"quantityBefore":{"type":"number"},"quantityAfter":{"type":"number"},"referenceId":{"anyOf":[{"type":"string"},{"type":"null"}]},"reason":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdById":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"}},"required":["id","itemId","type","delta","quantityBefore","quantityAfter","referenceId","createdById","createdAt"],"additionalProperties":false}},"pagination":{"type":"object","properties":{"page":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"totalPages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["page","limit","total","totalPages"],"additionalProperties":false}},"required":["movements","pagination"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["logistics:read"]}],"x-guliel-feature":"logistics","x-guliel-verb":"read","x-guliel-scope":"logistics:read"}},"/api/items/{id}/stock":{"post":{"tags":["logistics"],"summary":"Attach stock to an item","description":"Creates a new `stock` attached to the given item.\n\n**Scope:** `logistics:write`  \n**Endpoint:** `POST /api/items/{id}/stock`","operationId":"items.stock","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"add":{"type":"number","exclusiveMinimum":0},"set":{"type":"number","minimum":0},"note":{"type":"string"}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Updated item row with the new `quantity`. See /api/items/[id] GET for the canonical shape."}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Updated item row with the new `quantity`. See /api/items/[id] GET for the canonical shape."}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["logistics:write"]}],"x-guliel-feature":"logistics","x-guliel-verb":"write","x-guliel-scope":"logistics:write"}},"/api/notifications":{"get":{"tags":["users"],"summary":"List notifications","description":"Lists notifications the caller can see. Results are filtered by the caller's accessible organizations; many routes paginate via `page` and `limit`.\n\n**Scope:** `users:read`  \n**Endpoint:** `GET /api/notifications`","operationId":"notifications.notifications","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["UNREAD","READ","ARCHIVED"]}},{"name":"type","in":"query","required":false,"schema":{"type":"string"}},{"name":"organizationId","in":"query","required":false,"schema":{"type":"string","minLength":1}},{"name":"limit","in":"query","required":true,"schema":{"default":50,"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"notifications":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"userId":{"type":"string"},"organizationId":{"anyOf":[{"type":"string"},{"type":"null"}]},"type":{"type":"string"},"title":{"type":"string"},"message":{"type":"string"},"status":{"type":"string","description":"UNREAD | READ | ARCHIVED"},"actionUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"relatedType":{"anyOf":[{"type":"string"},{"type":"null"}]},"relatedId":{"anyOf":[{"type":"string"},{"type":"null"}]},"metadata":{"anyOf":[{},{"type":"null"}]},"createdAt":{"type":"string"},"readAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","userId","organizationId","type","title","message","status","actionUrl","relatedType","relatedId","metadata","createdAt","readAt"],"additionalProperties":false}},"unreadCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"unreadCountsByOrg":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"Per-org unread counts. The key `_null` holds notifications without an org (global)."}},"required":["notifications","unreadCount","unreadCountsByOrg"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:read"]}],"x-guliel-feature":"users","x-guliel-verb":"read","x-guliel-scope":"users:read"}},"/api/notifications/{id}":{"patch":{"tags":["users"],"summary":"Update a notification","description":"Updates an existing notification. Only the fields present in the request body are changed; omitted fields stay as-is.\n\n**Scope:** `users:write`  \n**Endpoint:** `PATCH /api/notifications/{id}`","operationId":"notifications.update","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["READ","ARCHIVED"]}},"required":["id","status"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"userId":{"type":"string"},"organizationId":{"anyOf":[{"type":"string"},{"type":"null"}]},"type":{"type":"string"},"title":{"type":"string"},"message":{"type":"string"},"status":{"type":"string"},"actionUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"relatedType":{"anyOf":[{"type":"string"},{"type":"null"}]},"relatedId":{"anyOf":[{"type":"string"},{"type":"null"}]},"metadata":{"anyOf":[{},{"type":"null"}]},"createdAt":{"type":"string"},"readAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","userId","organizationId","type","title","message","status","actionUrl","relatedType","relatedId","metadata","createdAt","readAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:write"]}],"x-guliel-feature":"users","x-guliel-verb":"write","x-guliel-scope":"users:write"},"delete":{"tags":["users"],"summary":"Delete a notification","description":"Deletes the notification. Some endpoints hard-delete the row, others soft-revoke (set `revokedAt`). Check the response shape.\n\n**Scope:** `users:write`  \n**Endpoint:** `DELETE /api/notifications/{id}`","operationId":"notifications.delete","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"deleted":{"type":"boolean"}},"required":["id","deleted"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:write"]}],"x-guliel-feature":"users","x-guliel-verb":"write","x-guliel-scope":"users:write"}},"/api/notifications/mark-all-read":{"post":{"tags":["users"],"summary":"Run mark all read (notifications)","description":"Performs the `mark-all-read` operation for the notifications feature.\n\n**Scope:** `users:write`  \n**Endpoint:** `POST /api/notifications/mark-all-read`","operationId":"notifications.mark_all_read","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{},"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true}},"required":["success"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true}},"required":["success"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:write"]}],"x-guliel-feature":"users","x-guliel-verb":"write","x-guliel-scope":"users:write"}},"/api/oauth-authorizations":{"get":{"tags":["users"],"summary":"List OAuth authorizations","description":"Lists OAuth authorizations the caller can see. Results are filtered by the caller's accessible organizations; many routes paginate via `page` and `limit`.\n\n**Scope:** `users:read`  \n**Auth sources:** `SESSION` only  \n**Endpoint:** `GET /api/oauth-authorizations`","operationId":"oauth_authorizations.oauth_authorizations","parameters":[],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"authorizations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"clientId":{"type":"string"},"clientName":{"type":"string"},"clientLogoUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"clientHomepageUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"isFirstParty":{"type":"boolean"},"scopes":{"type":"array","items":{"type":"string"}},"allOrgs":{"type":"boolean"},"organizationIds":{"type":"array","items":{"type":"string"}},"lastUsedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"activeTokenCount":{"type":"number"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","clientId","clientName","clientLogoUrl","clientHomepageUrl","isFirstParty","scopes","allOrgs","organizationIds","lastUsedAt","activeTokenCount","createdAt","updatedAt"],"additionalProperties":false}}},"required":["authorizations"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:read"]}],"x-guliel-feature":"users","x-guliel-verb":"read","x-guliel-allowed-sources":["SESSION"],"x-guliel-scope":"users:read"}},"/api/oauth-authorizations/{id}":{"get":{"tags":["users"],"summary":"Get an OAuth authorization","description":"Fetches a single OAuth authorization by id. Returns 404 if the OAuth authorization isn't in the caller's accessible organizations.\n\n**Scope:** `users:read`  \n**Auth sources:** `SESSION` only  \n**Endpoint:** `GET /api/oauth-authorizations/{id}`","operationId":"oauth_authorizations.get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"authorization":{"type":"object","properties":{"id":{"type":"string"},"clientId":{"type":"string"},"clientName":{"type":"string"},"clientLogoUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"clientHomepageUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"clientDescription":{"anyOf":[{"type":"string"},{"type":"null"}]},"isFirstParty":{"type":"boolean"},"scopes":{"type":"array","items":{"type":"string"}},"allOrgs":{"type":"boolean"},"organizationIds":{"type":"array","items":{"type":"string"}},"tokens":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"prefix":{"type":"string"},"expiresAt":{"type":"string"},"lastUsedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"}},"required":["id","prefix","expiresAt","lastUsedAt","createdAt"],"additionalProperties":false}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","clientId","clientName","clientLogoUrl","clientHomepageUrl","clientDescription","isFirstParty","scopes","allOrgs","organizationIds","tokens","createdAt","updatedAt"],"additionalProperties":false}},"required":["authorization"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:read"]}],"x-guliel-feature":"users","x-guliel-verb":"read","x-guliel-allowed-sources":["SESSION"],"x-guliel-scope":"users:read"},"delete":{"tags":["users"],"summary":"Delete an OAuth authorization","description":"Deletes the OAuth authorization. Some endpoints hard-delete the row, others soft-revoke (set `revokedAt`). Check the response shape.\n\n**Scope:** `users:write`  \n**Auth sources:** `SESSION` only  \n**Endpoint:** `DELETE /api/oauth-authorizations/{id}`","operationId":"oauth_authorizations.delete","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"revokedAt":{"type":"string"},"revokedTokenCount":{"type":"number"}},"required":["revokedAt","revokedTokenCount"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:write"]}],"x-guliel-feature":"users","x-guliel-verb":"write","x-guliel-allowed-sources":["SESSION"],"x-guliel-scope":"users:write"}},"/api/orders":{"get":{"tags":["orders"],"summary":"List orders","description":"Lists orders the caller can see. Results are filtered by the caller's accessible organizations; many routes paginate via `page` and `limit`.\n\n**Scope:** `orders:read`  \n**Endpoint:** `GET /api/orders`","operationId":"orders.orders","parameters":[{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}},{"name":"page","in":"query","required":true,"schema":{"default":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"name":"limit","in":"query","required":true,"schema":{"default":20,"type":"integer","minimum":1,"maximum":100}},{"name":"search","in":"query","required":true,"schema":{"default":"","type":"string"}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"supplierId","in":"query","required":false,"schema":{"type":"string"}},{"name":"sortBy","in":"query","required":true,"schema":{"default":"createdAt","type":"string","enum":["orderNumber","orderDate","subtotal","status","createdAt"]}},{"name":"sortOrder","in":"query","required":true,"schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"orders":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"supplierId":{"type":"string"},"orderNumber":{"type":"string"},"status":{"type":"string","description":"DRAFT | SENT | APPROVED | INVOICED | REJECTED | PAID"},"currency":{"type":"string"},"subtotal":{"type":"number"},"totalAmount":{"type":"number"},"orderDate":{"type":"string"},"expectedDeliveryDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"supplier":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"supplierOrganizationId":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","supplierOrganizationId"],"additionalProperties":false},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","supplierId","orderNumber","status","currency","subtotal","totalAmount","orderDate","expectedDeliveryDate","notes","supplier","createdAt","updatedAt"],"additionalProperties":false}},"pagination":{"type":"object","properties":{"page":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"totalPages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["page","limit","total","totalPages"],"additionalProperties":false}},"required":["orders","pagination"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["orders:read"]}],"x-guliel-feature":"orders","x-guliel-verb":"read","x-guliel-scope":"orders:read"},"post":{"tags":["orders"],"summary":"Create an order","description":"Creates a new order in the target organization. Returns the created record on success.\n\n**Scope:** `orders:write`  \n**Min role:** `CONTRIBUTOR` or higher  \n**Endpoint:** `POST /api/orders`","operationId":"orders.orders","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"organizationId":{"type":"string","minLength":1},"supplierId":{"type":"string","minLength":1},"currency":{"type":"string","minLength":1},"notes":{"type":"string"},"expectedDate":{"type":"string"},"items":{"minItems":1,"type":"array","items":{"type":"object","properties":{"itemId":{"type":"string"},"description":{"type":"string","minLength":1},"quantity":{"type":"number","exclusiveMinimum":0},"unitPrice":{"type":"number","minimum":0}},"required":["description","quantity","unitPrice"],"additionalProperties":false}}},"required":["organizationId","supplierId","currency","items"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"supplierId":{"type":"string"},"orderNumber":{"type":"string"},"status":{"type":"string","description":"DRAFT | SENT | APPROVED | INVOICED | REJECTED | PAID"},"currency":{"type":"string"},"subtotal":{"type":"number"},"totalAmount":{"type":"number"},"orderDate":{"type":"string"},"expectedDeliveryDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"supplier":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"supplierOrganizationId":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","supplierOrganizationId"],"additionalProperties":false},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","supplierId","orderNumber","status","currency","subtotal","totalAmount","orderDate","expectedDeliveryDate","notes","supplier","createdAt","updatedAt"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"supplierId":{"type":"string"},"orderNumber":{"type":"string"},"status":{"type":"string","description":"DRAFT | SENT | APPROVED | INVOICED | REJECTED | PAID"},"currency":{"type":"string"},"subtotal":{"type":"number"},"totalAmount":{"type":"number"},"orderDate":{"type":"string"},"expectedDeliveryDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"supplier":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"supplierOrganizationId":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","supplierOrganizationId"],"additionalProperties":false},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","supplierId","orderNumber","status","currency","subtotal","totalAmount","orderDate","expectedDeliveryDate","notes","supplier","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["orders:write"]}],"x-guliel-feature":"orders","x-guliel-verb":"write","x-guliel-required-role":"CONTRIBUTOR","x-guliel-scope":"orders:write"}},"/api/orders/{id}":{"get":{"tags":["orders"],"summary":"Get an order","description":"Fetches a single order by id. Returns 404 if the order isn't in the caller's accessible organizations.\n\n**Scope:** `orders:read`  \n**Endpoint:** `GET /api/orders/{id}`","operationId":"orders.get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"supplierId":{"type":"string"},"orderNumber":{"type":"string"},"status":{"type":"string"},"currency":{"type":"string"},"subtotal":{"type":"number"},"totalAmount":{"type":"number"},"orderDate":{"type":"string"},"expectedDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"supplier":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string"},"supplierOrganization":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"country":{"type":"string"},"registrationNumber":{"type":"string"},"address":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","country","registrationNumber","address"],"additionalProperties":false},{"type":"null"}]}},"required":["id","name","email","status","supplierOrganization"],"additionalProperties":false},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"itemId":{"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"type":"string"},"quantity":{"type":"number"},"unitPrice":{"type":"number"},"amount":{"type":"number"},"item":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"sku":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","sku"],"additionalProperties":false},{"type":"null"}]}},"required":["id","itemId","description","quantity","unitPrice","amount","item"],"additionalProperties":false}},"invoices":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"invoiceNumber":{"type":"string"},"status":{"type":"string"},"total":{"type":"number"},"currency":{"type":"string"}},"required":["id","invoiceNumber","status","total","currency"],"additionalProperties":false}},"expense":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"amount":{"type":"number"},"currency":{"type":"string"}},"required":["id","status","amount","currency"],"additionalProperties":false},{"type":"null"}]},"createdBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","supplierId","orderNumber","status","currency","subtotal","totalAmount","orderDate","expectedDate","notes","supplier","items","invoices","expense","createdBy","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["orders:read"]}],"x-guliel-feature":"orders","x-guliel-verb":"read","x-guliel-scope":"orders:read"},"put":{"tags":["orders"],"summary":"Update an order","description":"Replaces an existing order. All required fields must be supplied — omitted fields revert to their schema defaults.\n\n**Scope:** `orders:write`  \n**Endpoint:** `PUT /api/orders/{id}`","operationId":"orders.update","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"currency":{"type":"string","minLength":1},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"expectedDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"items":{"minItems":1,"type":"array","items":{"type":"object","properties":{"itemId":{"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"type":"string","minLength":1},"quantity":{"type":"number","exclusiveMinimum":0},"unitPrice":{"type":"number","minimum":0}},"required":["description","quantity","unitPrice"],"additionalProperties":false}}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"supplierId":{"type":"string"},"orderNumber":{"type":"string"},"status":{"type":"string"},"currency":{"type":"string"},"subtotal":{"type":"number"},"totalAmount":{"type":"number"},"orderDate":{"type":"string"},"expectedDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"supplier":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string"},"supplierOrganization":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"country":{"type":"string"},"registrationNumber":{"type":"string"},"address":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","country","registrationNumber","address"],"additionalProperties":false},{"type":"null"}]}},"required":["id","name","email","status","supplierOrganization"],"additionalProperties":false},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"itemId":{"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"type":"string"},"quantity":{"type":"number"},"unitPrice":{"type":"number"},"amount":{"type":"number"},"item":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"sku":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","sku"],"additionalProperties":false},{"type":"null"}]}},"required":["id","itemId","description","quantity","unitPrice","amount","item"],"additionalProperties":false}},"invoices":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"invoiceNumber":{"type":"string"},"status":{"type":"string"},"total":{"type":"number"},"currency":{"type":"string"}},"required":["id","invoiceNumber","status","total","currency"],"additionalProperties":false}},"expense":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"amount":{"type":"number"},"currency":{"type":"string"}},"required":["id","status","amount","currency"],"additionalProperties":false},{"type":"null"}]},"createdBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","supplierId","orderNumber","status","currency","subtotal","totalAmount","orderDate","expectedDate","notes","supplier","items","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["orders:write"]}],"x-guliel-feature":"orders","x-guliel-verb":"write","x-guliel-scope":"orders:write"},"patch":{"tags":["orders"],"summary":"Update an order","description":"Updates an existing order. Only the fields present in the request body are changed; omitted fields stay as-is.\n\n**Scope:** `orders:write`  \n**Endpoint:** `PATCH /api/orders/{id}`","operationId":"orders.update","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"currency":{"type":"string","minLength":1},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"expectedDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"items":{"minItems":1,"type":"array","items":{"type":"object","properties":{"itemId":{"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"type":"string","minLength":1},"quantity":{"type":"number","exclusiveMinimum":0},"unitPrice":{"type":"number","minimum":0}},"required":["description","quantity","unitPrice"],"additionalProperties":false}}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"supplierId":{"type":"string"},"orderNumber":{"type":"string"},"status":{"type":"string"},"currency":{"type":"string"},"subtotal":{"type":"number"},"totalAmount":{"type":"number"},"orderDate":{"type":"string"},"expectedDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"supplier":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string"},"supplierOrganization":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"country":{"type":"string"},"registrationNumber":{"type":"string"},"address":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","country","registrationNumber","address"],"additionalProperties":false},{"type":"null"}]}},"required":["id","name","email","status","supplierOrganization"],"additionalProperties":false},{"type":"null"}]},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"itemId":{"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"type":"string"},"quantity":{"type":"number"},"unitPrice":{"type":"number"},"amount":{"type":"number"},"item":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"sku":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","sku"],"additionalProperties":false},{"type":"null"}]}},"required":["id","itemId","description","quantity","unitPrice","amount","item"],"additionalProperties":false}},"invoices":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"invoiceNumber":{"type":"string"},"status":{"type":"string"},"total":{"type":"number"},"currency":{"type":"string"}},"required":["id","invoiceNumber","status","total","currency"],"additionalProperties":false}},"expense":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"amount":{"type":"number"},"currency":{"type":"string"}},"required":["id","status","amount","currency"],"additionalProperties":false},{"type":"null"}]},"createdBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","supplierId","orderNumber","status","currency","subtotal","totalAmount","orderDate","expectedDate","notes","supplier","items","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["orders:write"]}],"x-guliel-feature":"orders","x-guliel-verb":"write","x-guliel-scope":"orders:write"},"delete":{"tags":["orders"],"summary":"Delete an order","description":"Deletes the order. Some endpoints hard-delete the row, others soft-revoke (set `revokedAt`). Check the response shape.\n\n**Scope:** `orders:write`  \n**Endpoint:** `DELETE /api/orders/{id}`","operationId":"orders.delete","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true}},"required":["success"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["orders:write"]}],"x-guliel-feature":"orders","x-guliel-verb":"write","x-guliel-scope":"orders:write"}},"/api/orders/{id}/invoice":{"post":{"tags":["invoices"],"summary":"Attach invoice to an order","description":"Creates a new `invoice` attached to the given order.\n\n**Scope:** `invoices:write`  \n**Min role:** `CONTRIBUTOR` or higher  \n**Endpoint:** `POST /api/orders/{id}/invoice`","operationId":"orders.invoice","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"invoice":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"The freshly-created invoice. See /api/documents/[id] GET for the canonical shape."},"redirectUrl":{"type":"string","description":"Path the UI should navigate to so the user can edit the new invoice."}},"required":["invoice","redirectUrl"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"invoice":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"The freshly-created invoice. See /api/documents/[id] GET for the canonical shape."},"redirectUrl":{"type":"string","description":"Path the UI should navigate to so the user can edit the new invoice."}},"required":["invoice","redirectUrl"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["invoices:write"]}],"x-guliel-feature":"invoices","x-guliel-verb":"write","x-guliel-required-role":"CONTRIBUTOR","x-guliel-scope":"invoices:write"}},"/api/orders/{id}/status":{"post":{"tags":["orders"],"summary":"Update the order status","description":"Mutates the state machine of the order. Some transitions are restricted by role.\n\n**Scope:** `orders:write`  \n**Min role:** `CONTRIBUTOR` or higher  \n**Endpoint:** `POST /api/orders/{id}/status`","operationId":"orders.status","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["APPROVED","REJECTED"]},"note":{"type":"string"}},"required":["id","status"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Updated order row with relations rebuilt — see /api/orders/[id] GET for the canonical shape."}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Updated order row with relations rebuilt — see /api/orders/[id] GET for the canonical shape."}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["orders:write"]}],"x-guliel-feature":"orders","x-guliel-verb":"write","x-guliel-required-role":"CONTRIBUTOR","x-guliel-scope":"orders:write"}},"/api/organizations":{"get":{"tags":["organizations"],"summary":"List organizations","description":"Lists organizations the caller can see. Results are filtered by the caller's accessible organizations; many routes paginate via `page` and `limit`.\n\n**Scope:** `organizations:read`  \n**Endpoint:** `GET /api/organizations`","operationId":"organizations.organizations","parameters":[{"name":"page","in":"query","required":true,"schema":{"default":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"name":"limit","in":"query","required":true,"schema":{"default":10,"type":"integer","minimum":1,"maximum":100}},{"name":"search","in":"query","required":true,"schema":{"default":"","type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"organizations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"country":{"type":"string"},"registrationNumber":{"type":"string"},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"icon":{"anyOf":[{"type":"string"},{"type":"null"}]},"countrySpecificData":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"users":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"role":{"type":"string"},"userId":{"type":"string"},"user":{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false}},"required":["id","role","userId","user"],"additionalProperties":false}},"_count":{"type":"object","properties":{"counterpartiesOwning":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"invoices":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["counterpartiesOwning","invoices"],"additionalProperties":false},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","country","registrationNumber","address","icon","countrySpecificData","createdAt","updatedAt"],"additionalProperties":false}},"pagination":{"type":"object","properties":{"page":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"totalPages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["page","limit","total","totalPages"],"additionalProperties":false}},"required":["organizations","pagination"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["organizations:read"]}],"x-guliel-feature":"organizations","x-guliel-verb":"read","x-guliel-scope":"organizations:read"},"post":{"tags":["organizations"],"summary":"Create an organization","description":"Creates a new organization in the target organization. Returns the created record on success.\n\n**Scope:** `organizations:write`  \n**Endpoint:** `POST /api/organizations`","operationId":"organizations.organizations","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"name":{"type":"string","minLength":1},"country":{"type":"string","enum":["ISRAEL","SINGAPORE","USA","GERMANY","NETHERLANDS","SWEDEN","AUSTRIA","FINLAND","DENMARK","SPAIN","SLOVAKIA","IRELAND","LUXEMBOURG","CYPRUS","MALTA","SLOVENIA","CZECH_REPUBLIC","LITHUANIA","LATVIA","ESTONIA","NORWAY","ICELAND","UNITED_KINGDOM","SWITZERLAND","CANADA","AUSTRALIA","NEW_ZEALAND","UAE","BAHRAIN","OMAN","QATAR","KUWAIT","JAPAN","HONG_KONG","TAIWAN","THAILAND","INDONESIA","SOUTH_AFRICA","NIGERIA"]},"registrationNumber":{"type":"string","minLength":1},"address":{"type":"string"},"icon":{"type":"string"},"countrySpecificData":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["name","country","registrationNumber"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"country":{"type":"string"},"registrationNumber":{"type":"string"},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"icon":{"anyOf":[{"type":"string"},{"type":"null"}]},"countrySpecificData":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"users":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"role":{"type":"string"},"userId":{"type":"string"},"user":{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false}},"required":["id","role","userId","user"],"additionalProperties":false}},"_count":{"type":"object","properties":{"counterpartiesOwning":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"invoices":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["counterpartiesOwning","invoices"],"additionalProperties":false},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","country","registrationNumber","address","icon","countrySpecificData","createdAt","updatedAt"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"country":{"type":"string"},"registrationNumber":{"type":"string"},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"icon":{"anyOf":[{"type":"string"},{"type":"null"}]},"countrySpecificData":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"users":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"role":{"type":"string"},"userId":{"type":"string"},"user":{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false}},"required":["id","role","userId","user"],"additionalProperties":false}},"_count":{"type":"object","properties":{"counterpartiesOwning":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"invoices":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["counterpartiesOwning","invoices"],"additionalProperties":false},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","country","registrationNumber","address","icon","countrySpecificData","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["organizations:write"]}],"x-guliel-feature":"organizations","x-guliel-verb":"write","x-guliel-scope":"organizations:write"}},"/api/organizations/{id}":{"get":{"tags":["organizations"],"summary":"Get an organization","description":"Fetches a single organization by id. Returns 404 if the organization isn't in the caller's accessible organizations.\n\n**Scope:** `organizations:read`  \n**Endpoint:** `GET /api/organizations/{id}`","operationId":"organizations.get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"country":{"type":"string"},"registrationNumber":{"type":"string"},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"icon":{"anyOf":[{"type":"string"},{"type":"null"}]},"countrySpecificData":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"users":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"userId":{"type":"string"},"role":{"type":"string"},"user":{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false}},"required":["id","userId","role","user"],"additionalProperties":false}},"_count":{"type":"object","properties":{"counterpartiesOwning":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"invoices":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["counterpartiesOwning","invoices"],"additionalProperties":false},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","country","registrationNumber","address","icon","countrySpecificData","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["organizations:read"]}],"x-guliel-feature":"organizations","x-guliel-verb":"read","x-guliel-scope":"organizations:read"},"put":{"tags":["organizations"],"summary":"Update an organization","description":"Replaces an existing organization. All required fields must be supplied — omitted fields revert to their schema defaults.\n\n**Scope:** `organizations:write`  \n**Endpoint:** `PUT /api/organizations/{id}`","operationId":"organizations.update","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","minLength":1},"registrationNumber":{"type":"string","minLength":1},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"icon":{"anyOf":[{"type":"string"},{"type":"null"}]},"countrySpecificData":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"country":{"type":"string"},"registrationNumber":{"type":"string"},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"icon":{"anyOf":[{"type":"string"},{"type":"null"}]},"countrySpecificData":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"users":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"userId":{"type":"string"},"role":{"type":"string"},"user":{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false}},"required":["id","userId","role","user"],"additionalProperties":false}},"_count":{"type":"object","properties":{"counterpartiesOwning":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"invoices":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["counterpartiesOwning","invoices"],"additionalProperties":false},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","country","registrationNumber","address","icon","countrySpecificData","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["organizations:write"]}],"x-guliel-feature":"organizations","x-guliel-verb":"write","x-guliel-scope":"organizations:write"},"patch":{"tags":["organizations"],"summary":"Update an organization","description":"Updates an existing organization. Only the fields present in the request body are changed; omitted fields stay as-is.\n\n**Scope:** `organizations:write`  \n**Endpoint:** `PATCH /api/organizations/{id}`","operationId":"organizations.update","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","minLength":1},"registrationNumber":{"type":"string","minLength":1},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"icon":{"anyOf":[{"type":"string"},{"type":"null"}]},"countrySpecificData":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"country":{"type":"string"},"registrationNumber":{"type":"string"},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"icon":{"anyOf":[{"type":"string"},{"type":"null"}]},"countrySpecificData":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"users":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"userId":{"type":"string"},"role":{"type":"string"},"user":{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false}},"required":["id","userId","role","user"],"additionalProperties":false}},"_count":{"type":"object","properties":{"counterpartiesOwning":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"invoices":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["counterpartiesOwning","invoices"],"additionalProperties":false},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","country","registrationNumber","address","icon","countrySpecificData","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["organizations:write"]}],"x-guliel-feature":"organizations","x-guliel-verb":"write","x-guliel-scope":"organizations:write"},"delete":{"tags":["organizations"],"summary":"Delete an organization","description":"Deletes the organization. Some endpoints hard-delete the row, others soft-revoke (set `revokedAt`). Check the response shape.\n\n**Scope:** `organizations:write`  \n**Endpoint:** `DELETE /api/organizations/{id}`","operationId":"organizations.delete","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true}},"required":["success"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["organizations:write"]}],"x-guliel-feature":"organizations","x-guliel-verb":"write","x-guliel-scope":"organizations:write"}},"/api/organizations/{id}/icon":{"get":{"tags":["organizations"],"summary":"List icon for an organization","description":"Returns every `icon` row associated with the given organization.\n\n**Scope:** `organizations:read`  \n**Endpoint:** `GET /api/organizations/{id}/icon`","operationId":"organizations.icon","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["organizations:read"]}],"x-guliel-feature":"organizations","x-guliel-verb":"read","x-guliel-scope":"organizations:read"},"post":{"tags":["organizations"],"summary":"Attach icon to an organization","description":"Creates a new `icon` attached to the given organization.\n\n**Scope:** `organizations:write`  \n**Min role:** `MANAGER` or higher  \n**Endpoint:** `POST /api/organizations/{id}/icon`","operationId":"organizations.icon","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true},"icon":{"type":"string","description":"Same-origin URL where the freshly-uploaded icon can be fetched."}},"required":["success","icon"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true},"icon":{"type":"string","description":"Same-origin URL where the freshly-uploaded icon can be fetched."}},"required":["success","icon"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["organizations:write"]}],"x-guliel-feature":"organizations","x-guliel-verb":"write","x-guliel-required-role":"MANAGER","x-guliel-scope":"organizations:write"},"delete":{"tags":["organizations"],"summary":"Detach icon from an organization","description":"Removes the association without deleting the underlying record.\n\n**Scope:** `organizations:write`  \n**Min role:** `MANAGER` or higher  \n**Endpoint:** `DELETE /api/organizations/{id}/icon`","operationId":"organizations.icon","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true}},"required":["success"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["organizations:write"]}],"x-guliel-feature":"organizations","x-guliel-verb":"write","x-guliel-required-role":"MANAGER","x-guliel-scope":"organizations:write"}},"/api/organizations/{id}/members":{"get":{"tags":["users"],"summary":"List members for an organization","description":"Returns every `members` row associated with the given organization.\n\n**Scope:** `users:read`  \n**Endpoint:** `GET /api/organizations/{id}/members`","operationId":"organizations.members","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"members":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"userId":{"type":"string"},"organizationId":{"type":"string"},"role":{"type":"string","description":"MANAGER | CONTRIBUTOR | VIEWER"},"user":{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","userId","organizationId","role","user","createdAt","updatedAt"],"additionalProperties":false}}},"required":["members"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:read"]}],"x-guliel-feature":"users","x-guliel-verb":"read","x-guliel-scope":"users:read"},"post":{"tags":["users"],"summary":"Attach members to an organization","description":"Creates a new `members` attached to the given organization.\n\n**Scope:** `users:write`  \n**Endpoint:** `POST /api/organizations/{id}/members`","operationId":"organizations.members","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"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,}$"},"role":{"type":"string","enum":["MANAGER","CONTRIBUTOR","VIEWER"]}},"required":["id","email","role"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"userId":{"type":"string"},"organizationId":{"type":"string"},"role":{"type":"string","description":"MANAGER | CONTRIBUTOR | VIEWER"},"user":{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","userId","organizationId","role","user","createdAt","updatedAt"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"userId":{"type":"string"},"organizationId":{"type":"string"},"role":{"type":"string","description":"MANAGER | CONTRIBUTOR | VIEWER"},"user":{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","userId","organizationId","role","user","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:write"]}],"x-guliel-feature":"users","x-guliel-verb":"write","x-guliel-scope":"users:write"},"patch":{"tags":["users"],"summary":"Update members on an organization","description":"Mutates the `members` attached to the given organization.\n\n**Scope:** `users:write`  \n**Endpoint:** `PATCH /api/organizations/{id}/members`","operationId":"organizations.members","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"userId":{"type":"string","minLength":1},"role":{"type":"string","enum":["MANAGER","CONTRIBUTOR","VIEWER"]}},"required":["id","userId","role"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"userId":{"type":"string"},"organizationId":{"type":"string"},"role":{"type":"string","description":"MANAGER | CONTRIBUTOR | VIEWER"},"user":{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","userId","organizationId","role","user","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:write"]}],"x-guliel-feature":"users","x-guliel-verb":"write","x-guliel-scope":"users:write"},"delete":{"tags":["users"],"summary":"Detach members from an organization","description":"Removes the association without deleting the underlying record.\n\n**Scope:** `users:write`  \n**Endpoint:** `DELETE /api/organizations/{id}/members`","operationId":"organizations.members","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."},{"name":"userId","in":"query","required":true,"schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true}},"required":["success"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:write"]}],"x-guliel-feature":"users","x-guliel-verb":"write","x-guliel-scope":"users:write"}},"/api/organizations/{id}/tax-authority":{"get":{"tags":["integrations"],"summary":"List tax authority for an organization","description":"Returns every `tax-authority` row associated with the given organization.\n\n**Scope:** `integrations:read`  \n**Endpoint:** `GET /api/organizations/{id}/tax-authority`","operationId":"organizations.tax_authority","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"integrations":{"type":"array","items":{"type":"object","properties":{"integrationId":{"type":"string","description":"Stable identifier of the tax-authority integration (e.g. \"israel-shaam\")."},"name":{"type":"string"},"country":{"type":"string"},"connected":{"type":"boolean"},"lastValidatedAt":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["integrationId","name","country","connected","lastValidatedAt"],"additionalProperties":false}}},"required":["integrations"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["integrations:read"]}],"x-guliel-feature":"integrations","x-guliel-verb":"read","x-guliel-scope":"integrations:read"}},"/api/organizations/{id}/tax-authority/{integrationId}":{"get":{"tags":["integrations"],"summary":"List tax authority for an organization","description":"Returns every `tax-authority` row associated with the given organization.\n\n**Scope:** `integrations:read`  \n**Min role:** `MANAGER` or higher  \n**Endpoint:** `GET /api/organizations/{id}/tax-authority/{integrationId}`","operationId":"organizations.get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."},{"name":"integrationId","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `integrationId` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"integrationId":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"requiredFields":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"environment":{"type":"string","description":"sandbox | production"},"status":{"type":"object","properties":{"exists":{"type":"boolean"},"isActive":{"type":"boolean"},"isValidated":{"type":"boolean"},"lastValidatedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"validationError":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["exists","isActive","isValidated","lastValidatedAt","validationError"],"additionalProperties":false}},"required":["integrationId","name","description","requiredFields","environment","status"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["integrations:read"]}],"x-guliel-feature":"integrations","x-guliel-verb":"read","x-guliel-required-role":"MANAGER","x-guliel-scope":"integrations:read"},"post":{"tags":["integrations"],"summary":"Attach tax authority to an organization","description":"Creates a new `tax-authority` attached to the given organization.\n\n**Scope:** `integrations:write`  \n**Min role:** `MANAGER` or higher  \n**Endpoint:** `POST /api/organizations/{id}/tax-authority/{integrationId}`","operationId":"organizations.create","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."},{"name":"integrationId","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `integrationId` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"integrationId":{"type":"string"},"credentials":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"environment":{"default":"sandbox","type":"string","enum":["sandbox","production"]}},"required":["id","integrationId","credentials","environment"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true},"message":{"type":"string"}},"required":["success","message"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true},"message":{"type":"string"}},"required":["success","message"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["integrations:write"]}],"x-guliel-feature":"integrations","x-guliel-verb":"write","x-guliel-required-role":"MANAGER","x-guliel-scope":"integrations:write"},"delete":{"tags":["integrations"],"summary":"Detach tax authority from an organization","description":"Removes the association without deleting the underlying record.\n\n**Scope:** `integrations:write`  \n**Min role:** `MANAGER` or higher  \n**Endpoint:** `DELETE /api/organizations/{id}/tax-authority/{integrationId}`","operationId":"organizations.delete","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."},{"name":"integrationId","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `integrationId` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true},"message":{"type":"string"}},"required":["success","message"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["integrations:write"]}],"x-guliel-feature":"integrations","x-guliel-verb":"write","x-guliel-required-role":"MANAGER","x-guliel-scope":"integrations:write"}},"/api/organizations/{id}/tax-authority/{integrationId}/validate":{"post":{"tags":["integrations"],"summary":"Attach tax authority/validate to an organization","description":"Creates a new `tax-authority/validate` attached to the given organization.\n\n**Scope:** `integrations:write`  \n**Min role:** `MANAGER` or higher  \n**Endpoint:** `POST /api/organizations/{id}/tax-authority/{integrationId}/validate`","operationId":"organizations.validate","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."},{"name":"integrationId","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `integrationId` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"integrationId":{"type":"string"}},"required":["id","integrationId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"valid":{"type":"boolean"},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"details":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]}},"required":["valid"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"valid":{"type":"boolean"},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"details":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]}},"required":["valid"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["integrations:write"]}],"x-guliel-feature":"integrations","x-guliel-verb":"write","x-guliel-required-role":"MANAGER","x-guliel-scope":"integrations:write"}},"/api/payments":{"post":{"tags":["payments"],"summary":"Create a payment","description":"Creates a new payment in the target organization. Returns the created record on success.\n\n**Scope:** `payments:write`  \n**Min role:** `CONTRIBUTOR` or higher  \n**Endpoint:** `POST /api/payments`","operationId":"payments.payments","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"organizationId":{"type":"string"},"amount":{"type":"number","exclusiveMinimum":0},"paidAt":{"type":"string"},"method":{"anyOf":[{"type":"string"},{"type":"null"}]},"documentIds":{"minItems":1,"type":"array","items":{"type":"string"}},"allocations":{"minItems":1,"type":"array","items":{"type":"object","properties":{"lineId":{"type":"string"},"amount":{"type":"number","exclusiveMinimum":0}},"required":["lineId","amount"],"additionalProperties":false}},"allowUnallocated":{"type":"boolean"}},"required":["organizationId","amount","paidAt"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"amount":{"type":"number"},"paidAt":{"type":"string"},"method":{"anyOf":[{"type":"string"},{"type":"null"}]},"allocations":{"type":"array","items":{"type":"object","properties":{"lineId":{"type":"string"},"amount":{"type":"number","exclusiveMinimum":0}},"required":["lineId","amount"],"additionalProperties":false}},"unallocated":{"type":"number"},"documents":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"paidAmount":{"type":"number"},"total":{"type":"number"}},"required":["id","status","paidAmount","total"],"additionalProperties":false}}},"required":["id","organizationId","amount","paidAt","method","allocations","unallocated","documents"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"amount":{"type":"number"},"paidAt":{"type":"string"},"method":{"anyOf":[{"type":"string"},{"type":"null"}]},"allocations":{"type":"array","items":{"type":"object","properties":{"lineId":{"type":"string"},"amount":{"type":"number","exclusiveMinimum":0}},"required":["lineId","amount"],"additionalProperties":false}},"unallocated":{"type":"number"},"documents":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"paidAmount":{"type":"number"},"total":{"type":"number"}},"required":["id","status","paidAmount","total"],"additionalProperties":false}}},"required":["id","organizationId","amount","paidAt","method","allocations","unallocated","documents"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["payments:write"]}],"x-guliel-feature":"payments","x-guliel-verb":"write","x-guliel-required-role":"CONTRIBUTOR","x-guliel-scope":"payments:write"}},"/api/payments/{id}":{"delete":{"tags":["payments"],"summary":"Delete a payment","description":"Deletes the payment. Some endpoints hard-delete the row, others soft-revoke (set `revokedAt`). Check the response shape.\n\n**Scope:** `payments:write`  \n**Min role:** `CONTRIBUTOR` or higher  \n**Endpoint:** `DELETE /api/payments/{id}`","operationId":"payments.delete","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"reversed":{"type":"boolean"},"documentIds":{"type":"array","items":{"type":"string"},"description":"Documents whose settled status changed."}},"required":["reversed","documentIds"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["payments:write"]}],"x-guliel-feature":"payments","x-guliel-verb":"write","x-guliel-required-role":"CONTRIBUTOR","x-guliel-scope":"payments:write"}},"/api/reports":{"get":{"tags":["reports"],"summary":"List reports","description":"Lists reports the caller can see. Results are filtered by the caller's accessible organizations; many routes paginate via `page` and `limit`.\n\n**Scope:** `reports:read`  \n**Endpoint:** `GET /api/reports`","operationId":"reports.reports","parameters":[{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}},{"name":"type","in":"query","required":false,"schema":{"type":"string"}},{"name":"category","in":"query","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true},"reports":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"description":"Report definitions (name, description, parameters, columns). The full shape lives in src/lib/reports/types.ts:ReportDefinition."},"organizationCountry":{"type":"string"}},"required":["success","reports","organizationCountry"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["reports:read"]}],"x-guliel-feature":"reports","x-guliel-verb":"read","x-guliel-scope":"reports:read"}},"/api/reports/{reportType}":{"get":{"tags":["reports"],"summary":"Get a report","description":"Fetches a single report by id. Returns 404 if the report isn't in the caller's accessible organizations.\n\n**Scope:** `reports:read`  \n**Endpoint:** `GET /api/reports/{reportType}`","operationId":"reports.get","parameters":[{"name":"reportType","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `reportType` resolved from the URL."},{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Generated report data — shape varies by report type (rows, totals, charts, etc.). See src/lib/reports/types.ts:ReportData and the per-report adapter in src/lib/reports/generators/."}},"required":["success","data"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["reports:read"]}],"x-guliel-feature":"reports","x-guliel-verb":"read","x-guliel-scope":"reports:read"}},"/api/reports/{reportType}/schema":{"get":{"tags":["reports"],"summary":"List schema for a report","description":"Returns every `schema` row associated with the given report.\n\n**Scope:** `reports:read`  \n**Endpoint:** `GET /api/reports/{reportType}/schema`","operationId":"reports.schema","parameters":[{"name":"reportType","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `reportType` resolved from the URL."},{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true},"definition":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Report definition (name, description, columns, parameters). See src/lib/reports/types.ts:ReportDefinition for the full shape."}},"required":["success","definition"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["reports:read"]}],"x-guliel-feature":"reports","x-guliel-verb":"read","x-guliel-scope":"reports:read"}},"/api/settings":{"get":{"tags":["settings"],"summary":"List settingses","description":"Lists settingses the caller can see. Results are filtered by the caller's accessible organizations; many routes paginate via `page` and `limit`.\n\n**Scope:** `settings:read`  \n**Endpoint:** `GET /api/settings`","operationId":"settings.settings","parameters":[],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"userId":{"type":"string"},"theme":{"type":"string","description":"light | dark | system"},"language":{"type":"string"},"defaultOrganizationId":{"anyOf":[{"type":"string"},{"type":"null"}]},"preferences":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","userId","theme","language","defaultOrganizationId","preferences","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["settings:read"]}],"x-guliel-feature":"settings","x-guliel-verb":"read","x-guliel-scope":"settings:read"},"put":{"tags":["settings"],"summary":"Update a settings","description":"Replaces an existing settings. All required fields must be supplied — omitted fields revert to their schema defaults.\n\n**Scope:** `settings:write`  \n**Endpoint:** `PUT /api/settings`","operationId":"settings.settings","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"theme":{"type":"string","enum":["light","dark","system"]},"language":{"type":"string"},"defaultOrganizationId":{"anyOf":[{"type":"string"},{"type":"null"}]},"preferences":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"userId":{"type":"string"},"theme":{"type":"string","description":"light | dark | system"},"language":{"type":"string"},"defaultOrganizationId":{"anyOf":[{"type":"string"},{"type":"null"}]},"preferences":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","userId","theme","language","defaultOrganizationId","preferences","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["settings:write"]}],"x-guliel-feature":"settings","x-guliel-verb":"write","x-guliel-scope":"settings:write"}},"/api/supplier-orders":{"get":{"tags":["orders"],"summary":"List supplier orders","description":"Lists supplier orders the caller can see. Results are filtered by the caller's accessible organizations; many routes paginate via `page` and `limit`.\n\n**Scope:** `orders:read`  \n**Endpoint:** `GET /api/supplier-orders`","operationId":"supplier_orders.supplier_orders","parameters":[{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}},{"name":"page","in":"query","required":true,"schema":{"default":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"name":"limit","in":"query","required":true,"schema":{"default":20,"type":"integer","minimum":1,"maximum":100}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","required":true,"schema":{"default":"","type":"string"}},{"name":"clientOrgId","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"orders":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string","description":"The CLIENT org that placed the order (not the supplier-side org)."},"supplierId":{"anyOf":[{"type":"string"},{"type":"null"}]},"counterpartyId":{"anyOf":[{"type":"string"},{"type":"null"}]},"orderNumber":{"type":"string"},"status":{"type":"string"},"currency":{"type":"string"},"subtotal":{"type":"number"},"orderDate":{"type":"string"},"expectedDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"organization":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"country":{"type":"string"}},"required":["id","name","country"],"additionalProperties":false},{"type":"null"}]},"supplier":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"The supplier Counterparty edge, with display name resolved through the linked party."},"items":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"_count":{"type":"object","properties":{"invoices":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["invoices"],"additionalProperties":false},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","supplierId","counterpartyId","orderNumber","status","currency","subtotal","orderDate","expectedDate","organization","supplier","items","createdAt","updatedAt"],"additionalProperties":false}},"pagination":{"type":"object","properties":{"page":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"totalPages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["page","limit","total","totalPages"],"additionalProperties":false}},"required":["orders","pagination"],"additionalProperties":false,"description":"Orders the caller's org has received as a supplier. Inverse of /api/orders, which lists orders placed by the caller's org."}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["orders:read"]}],"x-guliel-feature":"orders","x-guliel-verb":"read","x-guliel-scope":"orders:read"}},"/api/supplier-orders/{id}":{"get":{"tags":["orders"],"summary":"Get a supplier order","description":"Fetches a single supplier order by id. Returns 404 if the supplier order isn't in the caller's accessible organizations.\n\n**Scope:** `orders:read`  \n**Endpoint:** `GET /api/supplier-orders/{id}`","operationId":"supplier_orders.get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"supplierId":{"anyOf":[{"type":"string"},{"type":"null"}]},"counterpartyId":{"anyOf":[{"type":"string"},{"type":"null"}]},"orderNumber":{"type":"string"},"status":{"type":"string"},"currency":{"type":"string"},"subtotal":{"type":"number"},"orderDate":{"type":"string"},"expectedDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"organization":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"country":{"type":"string"},"address":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","country","address"],"additionalProperties":false},{"type":"null"}]},"supplier":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"supplierOrganizationId":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","email","supplierOrganizationId"],"additionalProperties":false},{"type":"null"}],"description":"The supplier Counterparty edge — display fields resolved through the linked party; `supplierOrganizationId` maps to Counterparty.otherOrganizationId."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"itemId":{"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"type":"string"},"quantity":{"type":"number"},"unitPrice":{"type":"number"},"amount":{"type":"number"},"item":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"sku":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","sku"],"additionalProperties":false},{"type":"null"}]}},"required":["id","itemId","description","quantity","unitPrice","amount","item"],"additionalProperties":false}},"invoices":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"invoiceNumber":{"type":"string"},"status":{"type":"string"},"total":{"type":"number"},"currency":{"type":"string"}},"required":["id","invoiceNumber","status","total","currency"],"additionalProperties":false}},"createdBy":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string"}},"required":["id","name","email"],"additionalProperties":false},{"type":"null"}]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","supplierId","counterpartyId","orderNumber","status","currency","subtotal","orderDate","expectedDate","notes","organization","supplier","items","invoices","createdBy","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["orders:read"]}],"x-guliel-feature":"orders","x-guliel-verb":"read","x-guliel-scope":"orders:read"}},"/api/suppliers":{"get":{"tags":["suppliers"],"summary":"List suppliers","description":"Lists suppliers the caller can see. Results are filtered by the caller's accessible organizations; many routes paginate via `page` and `limit`.\n\n**Scope:** `suppliers:read`  \n**Endpoint:** `GET /api/suppliers`","operationId":"suppliers.suppliers","parameters":[{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}},{"name":"page","in":"query","required":true,"schema":{"default":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"name":"limit","in":"query","required":true,"schema":{"default":20,"type":"integer","minimum":1,"maximum":100}},{"name":"search","in":"query","required":true,"schema":{"default":"","type":"string"}},{"name":"status","in":"query","required":true,"schema":{"default":"ACTIVE","type":"string"}},{"name":"sortBy","in":"query","required":true,"schema":{"default":"createdAt","type":"string","enum":["name","email","status","createdAt"]}},{"name":"sortOrder","in":"query","required":true,"schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"suppliers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Counterparty edge id."},"organizationId":{"type":"string"},"kind":{"type":"string","enum":["ORGANIZATION","INDIVIDUAL"],"description":"ORGANIZATION = a business supplier (linked Organization); INDIVIDUAL = a freelance/private-person supplier."},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"contactName":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"registrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"defaultCurrencies":{"type":"array","items":{"type":"string"}},"status":{"type":"string","description":"ACTIVE | PENDING | INACTIVE — pending suppliers represent unaccepted invitations."},"invitationMethod":{"anyOf":[{"type":"string"},{"type":"null"}]},"invitedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"acceptedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"acceptedByUserId":{"anyOf":[{"type":"string"},{"type":"null"}]},"supplierOrganizationId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Set when this supplier is itself an Organization (business supplier). Maps to Counterparty.otherOrganizationId."},"activeOrderCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","kind","name","contactName","email","phone","address","country","registrationNumber","defaultCurrencies","status","invitationMethod","invitedAt","acceptedAt","acceptedByUserId","supplierOrganizationId","activeOrderCount","createdAt","updatedAt"],"additionalProperties":false}},"pagination":{"type":"object","properties":{"page":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"totalPages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["page","limit","total","totalPages"],"additionalProperties":false}},"required":["suppliers","pagination"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["suppliers:read"]}],"x-guliel-feature":"suppliers","x-guliel-verb":"read","x-guliel-scope":"suppliers:read"},"post":{"tags":["suppliers"],"summary":"Create a supplier","description":"Creates a new supplier in the target organization. Returns the created record on success.\n\n**Scope:** `suppliers:write`  \n**Min role:** `CONTRIBUTOR` or higher  \n**Endpoint:** `POST /api/suppliers`","operationId":"suppliers.suppliers","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"organizationId":{"type":"string","minLength":1},"mode":{"default":"email","type":"string","enum":["email","link","manual"]},"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"},"phone":{"type":"string"},"address":{"type":"string"},"country":{"type":"string"},"registrationNumber":{"type":"string"}},"required":["organizationId","mode"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","description":"Counterparty edge id."},"organizationId":{"type":"string"},"kind":{"type":"string","enum":["ORGANIZATION","INDIVIDUAL"],"description":"ORGANIZATION = a business supplier (linked Organization); INDIVIDUAL = a freelance/private-person supplier."},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"contactName":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"registrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"defaultCurrencies":{"type":"array","items":{"type":"string"}},"status":{"type":"string","description":"ACTIVE | PENDING | INACTIVE — pending suppliers represent unaccepted invitations."},"invitationMethod":{"anyOf":[{"type":"string"},{"type":"null"}]},"invitedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"acceptedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"acceptedByUserId":{"anyOf":[{"type":"string"},{"type":"null"}]},"supplierOrganizationId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Set when this supplier is itself an Organization (business supplier). Maps to Counterparty.otherOrganizationId."},"activeOrderCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","kind","name","contactName","email","phone","address","country","registrationNumber","defaultCurrencies","status","invitationMethod","invitedAt","acceptedAt","acceptedByUserId","supplierOrganizationId","createdAt","updatedAt"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","description":"Counterparty edge id."},"organizationId":{"type":"string"},"kind":{"type":"string","enum":["ORGANIZATION","INDIVIDUAL"],"description":"ORGANIZATION = a business supplier (linked Organization); INDIVIDUAL = a freelance/private-person supplier."},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"contactName":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"registrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"defaultCurrencies":{"type":"array","items":{"type":"string"}},"status":{"type":"string","description":"ACTIVE | PENDING | INACTIVE — pending suppliers represent unaccepted invitations."},"invitationMethod":{"anyOf":[{"type":"string"},{"type":"null"}]},"invitedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"acceptedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"acceptedByUserId":{"anyOf":[{"type":"string"},{"type":"null"}]},"supplierOrganizationId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Set when this supplier is itself an Organization (business supplier). Maps to Counterparty.otherOrganizationId."},"activeOrderCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","kind","name","contactName","email","phone","address","country","registrationNumber","defaultCurrencies","status","invitationMethod","invitedAt","acceptedAt","acceptedByUserId","supplierOrganizationId","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["suppliers:write"]}],"x-guliel-feature":"suppliers","x-guliel-verb":"write","x-guliel-required-role":"CONTRIBUTOR","x-guliel-scope":"suppliers:write"}},"/api/suppliers/{id}":{"get":{"tags":["suppliers"],"summary":"Get a supplier","description":"Fetches a single supplier by id. Returns 404 if the supplier isn't in the caller's accessible organizations.\n\n**Scope:** `suppliers:read`  \n**Endpoint:** `GET /api/suppliers/{id}`","operationId":"suppliers.get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"kind":{"anyOf":[{"type":"string","enum":["ORGANIZATION","INDIVIDUAL"]},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"registrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"defaultCurrencies":{"type":"array","items":{"type":"string"}},"status":{"type":"string"},"acceptedByUserId":{"anyOf":[{"type":"string"},{"type":"null"}]},"supplierOrganizationId":{"anyOf":[{"type":"string"},{"type":"null"}]},"supplierOrganization":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"country":{"type":"string"},"registrationNumber":{"type":"string"},"address":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","country","registrationNumber","address"],"additionalProperties":false},{"type":"null"}]},"activeOrderCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","kind","name","email","phone","address","country","registrationNumber","defaultCurrencies","status","acceptedByUserId","supplierOrganizationId","supplierOrganization","activeOrderCount","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["suppliers:read"]}],"x-guliel-feature":"suppliers","x-guliel-verb":"read","x-guliel-scope":"suppliers:read"},"put":{"tags":["suppliers"],"summary":"Update a supplier","description":"Replaces an existing supplier. All required fields must be supplied — omitted fields revert to their schema defaults.\n\n**Scope:** `suppliers:write`  \n**Endpoint:** `PUT /api/suppliers/{id}`","operationId":"suppliers.update","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string","minLength":1},{"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"},{"type":"null"}]},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"registrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"kind":{"anyOf":[{"type":"string","enum":["ORGANIZATION","INDIVIDUAL"]},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"registrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"defaultCurrencies":{"type":"array","items":{"type":"string"}},"status":{"type":"string"},"acceptedByUserId":{"anyOf":[{"type":"string"},{"type":"null"}]},"supplierOrganizationId":{"anyOf":[{"type":"string"},{"type":"null"}]},"supplierOrganization":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"country":{"type":"string"},"registrationNumber":{"type":"string"},"address":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","country","registrationNumber","address"],"additionalProperties":false},{"type":"null"}]},"activeOrderCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","kind","name","email","phone","address","country","registrationNumber","defaultCurrencies","status","acceptedByUserId","supplierOrganizationId","supplierOrganization","activeOrderCount","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["suppliers:write"]}],"x-guliel-feature":"suppliers","x-guliel-verb":"write","x-guliel-scope":"suppliers:write"},"patch":{"tags":["suppliers"],"summary":"Update a supplier","description":"Updates an existing supplier. Only the fields present in the request body are changed; omitted fields stay as-is.\n\n**Scope:** `suppliers:write`  \n**Endpoint:** `PATCH /api/suppliers/{id}`","operationId":"suppliers.update","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string","minLength":1},{"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"},{"type":"null"}]},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"registrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"kind":{"anyOf":[{"type":"string","enum":["ORGANIZATION","INDIVIDUAL"]},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]},"phone":{"anyOf":[{"type":"string"},{"type":"null"}]},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"registrationNumber":{"anyOf":[{"type":"string"},{"type":"null"}]},"defaultCurrencies":{"type":"array","items":{"type":"string"}},"status":{"type":"string"},"acceptedByUserId":{"anyOf":[{"type":"string"},{"type":"null"}]},"supplierOrganizationId":{"anyOf":[{"type":"string"},{"type":"null"}]},"supplierOrganization":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"country":{"type":"string"},"registrationNumber":{"type":"string"},"address":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","country","registrationNumber","address"],"additionalProperties":false},{"type":"null"}]},"activeOrderCount":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","organizationId","kind","name","email","phone","address","country","registrationNumber","defaultCurrencies","status","acceptedByUserId","supplierOrganizationId","supplierOrganization","activeOrderCount","createdAt","updatedAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["suppliers:write"]}],"x-guliel-feature":"suppliers","x-guliel-verb":"write","x-guliel-scope":"suppliers:write"},"delete":{"tags":["suppliers"],"summary":"Delete a supplier","description":"Deletes the supplier. Some endpoints hard-delete the row, others soft-revoke (set `revokedAt`). Check the response shape.\n\n**Scope:** `suppliers:write`  \n**Endpoint:** `DELETE /api/suppliers/{id}`","operationId":"suppliers.delete","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."},{"name":"mode","in":"query","required":false,"schema":{"anyOf":[{"type":"string","const":"soft"},{"type":"string","const":"hard"}]}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true},"mode":{"anyOf":[{"type":"string","const":"hard"},{"type":"string","const":"soft"}],"description":"Which delete path executed — hard removes the row, soft sets status=INACTIVE to preserve order history."}},"required":["success","mode"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["suppliers:write"]}],"x-guliel-feature":"suppliers","x-guliel-verb":"write","x-guliel-scope":"suppliers:write"}},"/api/suppliers/{id}/items":{"get":{"tags":["suppliers"],"summary":"List items for a supplier","description":"Returns every `items` row associated with the given supplier.\n\n**Scope:** `suppliers:read`  \n**Endpoint:** `GET /api/suppliers/{id}/items`","operationId":"suppliers.items","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"sku":{"anyOf":[{"type":"string"},{"type":"null"}]},"unitPrice":{"anyOf":[{"type":"number"},{"type":"null"}]},"currency":{"anyOf":[{"type":"string"},{"type":"null"}]},"isActive":{"type":"boolean"},"availableForExternalOrder":{"type":"boolean"}},"required":["id","name","description","sku","unitPrice","currency","isActive","availableForExternalOrder"],"additionalProperties":false}}},"required":["items"],"additionalProperties":false,"description":"Supplier-published catalog. Empty for individual suppliers (no linked Organization)."}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["suppliers:read"]}],"x-guliel-feature":"suppliers","x-guliel-verb":"read","x-guliel-scope":"suppliers:read"}},"/api/suppliers/{id}/resend-invitation":{"post":{"tags":["suppliers"],"summary":"Attach resend invitation to a supplier","description":"Creates a new `resend-invitation` attached to the given supplier.\n\n**Scope:** `suppliers:write`  \n**Endpoint:** `POST /api/suppliers/{id}/resend-invitation`","operationId":"suppliers.resend_invitation","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"supplier":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","description":"Counterparty status — PENDING while the invitation is outstanding."},"invitedEmail":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Resolved recipient email; null if the supplier has no email on file."},"invitedAt":{"type":"string","description":"ISO timestamp of when the (re)invitation was issued."}},"required":["id","status","invitedEmail","invitedAt"],"additionalProperties":false},"inviteUrl":{"type":"string","description":"Pre-signed invitation acceptance URL the recipient can open."},"emailSent":{"type":"boolean","description":"False if the supplier had no email on file; the inviteUrl still works."}},"required":["supplier","inviteUrl","emailSent"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"supplier":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","description":"Counterparty status — PENDING while the invitation is outstanding."},"invitedEmail":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Resolved recipient email; null if the supplier has no email on file."},"invitedAt":{"type":"string","description":"ISO timestamp of when the (re)invitation was issued."}},"required":["id","status","invitedEmail","invitedAt"],"additionalProperties":false},"inviteUrl":{"type":"string","description":"Pre-signed invitation acceptance URL the recipient can open."},"emailSent":{"type":"boolean","description":"False if the supplier had no email on file; the inviteUrl still works."}},"required":["supplier","inviteUrl","emailSent"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["suppliers:write"]}],"x-guliel-feature":"suppliers","x-guliel-verb":"write","x-guliel-scope":"suppliers:write"}},"/api/suppliers/export/csv":{"get":{"tags":["suppliers"],"summary":"Export suppliers as CSV","description":"Streams the caller's suppliers as a CSV file. Filter parameters scope the export the same way the list endpoint does.\n\n**Scope:** `suppliers:read`  \n**Endpoint:** `GET /api/suppliers/export/csv`","operationId":"suppliers.csv","parameters":[{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["suppliers:read"]}],"x-guliel-feature":"suppliers","x-guliel-verb":"read","x-guliel-scope":"suppliers:read"}},"/api/user/organizations":{"get":{"tags":["organizations"],"summary":"Get organizations (users)","description":"Returns the `organizations` data for the users feature.\n\n**Scope:** `organizations:read`  \n**Endpoint:** `GET /api/user/organizations`","operationId":"user.organizations","parameters":[],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"country":{"type":"string"},"icon":{"anyOf":[{"type":"string"},{"type":"null"}]},"registrationNumber":{"type":"string"},"address":{"anyOf":[{"type":"string"},{"type":"null"}]},"countrySpecificData":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"role":{"type":"string","description":"Caller's role in this org — MANAGER | CONTRIBUTOR | VIEWER."}},"required":["id","name","country","icon","registrationNumber","address","countrySpecificData","role"],"additionalProperties":false}}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["organizations:read"]}],"x-guliel-feature":"organizations","x-guliel-verb":"read","x-guliel-scope":"organizations:read"}},"/api/users":{"get":{"tags":["users"],"summary":"List users","description":"Lists users the caller can see. Results are filtered by the caller's accessible organizations; many routes paginate via `page` and `limit`.\n\n**Scope:** `users:read`  \n**Min role:** `MANAGER` or higher  \n**Endpoint:** `GET /api/users`","operationId":"users.users","parameters":[{"name":"organizationId","in":"query","required":true,"schema":{"type":"string","minLength":1}},{"name":"page","in":"query","required":true,"schema":{"default":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"name":"limit","in":"query","required":true,"schema":{"default":10,"type":"integer","minimum":1,"maximum":100}},{"name":"search","in":"query","required":true,"schema":{"default":"","type":"string"}},{"name":"sortBy","in":"query","required":true,"schema":{"default":"name","type":"string","enum":["name","email","createdAt","role"]}},{"name":"sortOrder","in":"query","required":true,"schema":{"default":"asc","type":"string","enum":["asc","desc"]}},{"name":"role","in":"query","required":false,"schema":{"type":"string","enum":["MANAGER","CONTRIBUTOR","VIEWER"]}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"users":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"orgRole":{"type":"string"},"organizations":{"type":"array","items":{"type":"object","properties":{"role":{"type":"string"},"organization":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false}},"required":["role","organization"],"additionalProperties":false}},"createdAt":{"type":"string"}},"required":["id","email","name","orgRole","organizations","createdAt"],"additionalProperties":false}},"pagination":{"type":"object","properties":{"page":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"totalPages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["page","limit","total","totalPages"],"additionalProperties":false}},"required":["users","pagination"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:read"]}],"x-guliel-feature":"users","x-guliel-verb":"read","x-guliel-required-role":"MANAGER","x-guliel-scope":"users:read"},"post":{"tags":["users"],"summary":"Create an user","description":"Creates a new user in the target organization. Returns the created record on success.\n\n**Scope:** `users:write`  \n**Min role:** `MANAGER` or higher  \n**Endpoint:** `POST /api/users`","operationId":"users.users","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/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","minLength":1},"organizationId":{"type":"string","minLength":1},"orgRole":{"type":"string","enum":["MANAGER","CONTRIBUTOR","VIEWER"]}},"required":["email","name","organizationId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"}},"required":["id","email","name","createdAt"],"additionalProperties":false}}}},"201":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"}},"required":["id","email","name","createdAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:write"]}],"x-guliel-feature":"users","x-guliel-verb":"write","x-guliel-required-role":"MANAGER","x-guliel-scope":"users:write"}},"/api/users/{id}":{"get":{"tags":["users"],"summary":"Get an user","description":"Fetches a single user by id. Returns 404 if the user isn't in the caller's accessible organizations.\n\n**Scope:** `users:read`  \n**Endpoint:** `GET /api/users/{id}`","operationId":"users.get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"},"organizations":{"type":"array","items":{"type":"object","properties":{"role":{"type":"string"},"organization":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false}},"required":["role","organization"],"additionalProperties":false}}},"required":["id","email","name","createdAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:read"]}],"x-guliel-feature":"users","x-guliel-verb":"read","x-guliel-scope":"users:read"},"put":{"tags":["users"],"summary":"Update an user","description":"Replaces an existing user. All required fields must be supplied — omitted fields revert to their schema defaults.\n\n**Scope:** `users:write`  \n**Endpoint:** `PUT /api/users/{id}`","operationId":"users.update","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","minLength":1},"password":{"type":"string","minLength":6}},"required":["id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string"}},"required":["id","email","name","createdAt"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:write"]}],"x-guliel-feature":"users","x-guliel-verb":"write","x-guliel-scope":"users:write"},"patch":{"tags":["users"],"summary":"Update an user","description":"Updates an existing user. Only the fields present in the request body are changed; omitted fields stay as-is.\n\n**Scope:** `users:write`  \n**Endpoint:** `PATCH /api/users/{id}`","operationId":"users.update","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string"},"organizationId":{"type":"string"},"role":{"type":"string","enum":["MANAGER","CONTRIBUTOR","VIEWER"]}},"required":["id","organizationId","role"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true}},"required":["success"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:write"]}],"x-guliel-feature":"users","x-guliel-verb":"write","x-guliel-scope":"users:write"},"delete":{"tags":["users"],"summary":"Delete an user","description":"Deletes the user. Some endpoints hard-delete the row, others soft-revoke (set `revokedAt`). Check the response shape.\n\n**Scope:** `users:write`  \n**Endpoint:** `DELETE /api/users/{id}`","operationId":"users.delete","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Path parameter `id` resolved from the URL."}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"success":{"type":"boolean","const":true}},"required":["success"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimit"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:write"]}],"x-guliel-feature":"users","x-guliel-verb":"write","x-guliel-scope":"users:write"}},"/api/users/search":{"get":{"tags":["users"],"summary":"Get search (users)","description":"Returns the `search` data for the users feature.\n\n**Scope:** `users:read`  \n**Endpoint:** `GET /api/users/search`","operationId":"users.search","parameters":[{"name":"q","in":"query","required":true,"schema":{"default":"","type":"string"}},{"name":"excludeOrgId","in":"query","required":true,"schema":{"type":"string","minLength":1}},{"name":"limit","in":"query","required":true,"schema":{"default":10,"type":"integer","minimum":1,"maximum":20}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"users":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","email","name"],"additionalProperties":false}}},"required":["users"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/Validation"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/Internal"}},"security":[{"apiKey":["users:read"]}],"x-guliel-feature":"users","x-guliel-verb":"read","x-guliel-scope":"users:read"}}},"components":{"schemas":{"ApiError":{"type":"object","required":["error","code"],"properties":{"error":{"type":"string","description":"Human-readable error message."},"code":{"type":"string","enum":["UNAUTHENTICATED","REVOKED","EXPIRED","ORG_DENIED","SCOPE_DENIED","ROLE_DENIED","VALIDATION","RATE_LIMIT","NOT_FOUND","CONFLICT","INTERNAL"],"description":"Stable error code — clients can branch on this."},"details":{"type":"object","description":"Optional context (e.g. `required.scope`, validation issues)."}}}},"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","bearerFormat":"Guliel API key (gli_live_* in prod, gli_test_* in dev). See /dashboard/developer."},"oauth2":{"type":"oauth2","description":"Phase 3 — declared in advance so the spec is stable across releases.","flows":{"authorizationCode":{"authorizationUrl":"/oauth/authorize","tokenUrl":"/oauth/token","scopes":{"*:read":"Read every feature","*:write":"Write every feature"}}}}},"responses":{"Validation":{"description":"Validation error — request body or query params failed Zod parsing. `details` carries Zod issues.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"Unauthenticated":{"description":"No credentials, invalid bearer token, or expired/revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"Forbidden":{"description":"Authentication succeeded but authorization failed (ORG_DENIED / SCOPE_DENIED / ROLE_DENIED).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"RateLimit":{"description":"Per-credential rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"Internal":{"description":"Unhandled error in the route handler. Server-side issue; safe to retry idempotent calls.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}},"security":[{"apiKey":[]}]}