{"openapi":"3.1.0","info":{"title":"Filmo Public API","termsOfService":"https://www.filmo.io/legal/terms","contact":{"name":"Filmo API support","url":"https://www.filmo.io/help"},"license":{"name":"Filmo Terms of Service","url":"https://www.filmo.io/legal/terms"},"version":"1.0.0","description":"Filmo public REST API for third-party integrations (CRM, web forms, inventory tools, schedule sync). Surface **v1**, versioned: stable from `1.0.0` on (see *Versioning and lifecycle*).\n\n## Authentication\n\nEvery operation requires an **API key** sent as a *bearer token*:\n\n```\nAuthorization: Bearer fk_live_xxxxxxxxxxxxxxxxxxxxxxxx\n```\n\nKeys are generated in Filmo from **Ajustes → API y MCP** (Settings → API and MCP) (administrators only). Each key carries a set of *scopes* (permissions) that bound which operations it may call. Store the key securely: it is shown only once and amounts to programmatic access to the data of your company. This documentation is public; what is restricted is the **credential**, never reading the documentation.\n\n## Response envelope\n\nEvery response shares a uniform envelope in `application/json`:\n\n- **List**: `{ \"data\": [ ... ], \"pagination\": { \"nextCursor\": string|null, \"hasMore\": boolean, \"total\"?: integer } }`.\n- **Single resource**: `{ \"data\": { ... } }`.\n- **Error**: an RFC 9457 problem in `application/problem+json`: `{ \"type\", \"title\", \"status\", \"code\", \"detail\", \"requestId\", \"errors\"?, \"requiredScope\"?, \"requiredAddon\"? }` (see *Errors*).\n\nEvery response carries an `X-Request-Id` header; error bodies repeat it as `requestId`. Quote it when contacting support.\n\nMonetary amounts are always serialized as a **decimal string** with two decimals and ROUND_HALF_UP rounding (for example `\"1234.50\"`), never as a floating-point number, so that no precision is lost. Dates are **ISO 8601** strings in UTC (`date-time`). Where a write accepts a bare day (`YYYY-MM-DD`: only the workflow surface does; this REST contract and the MCP tools require an instant with offset), it is read in the **business timezone** of the account: an order takes the account's default delivery time for `startDate` and default return time for `endDate`; a project takes the start of the day. An instant with an offset is stored as given.\n\n## Pagination\n\nLists paginate by **opaque cursor**. Request the first page with `limit` (default 50, maximum 500) and, while `pagination.hasMore` is `true`, call again passing `cursor=<pagination.nextCursor>` with the same `limit`. The cursor encodes the internal offset; treat it as opaque (do not build it or interpret it). Pass `includeTotal=true` to receive `pagination.total`, the number of results matching the filters across all pages; it is omitted otherwise. Every list has a deterministic, stable order (newest first unless the operation says otherwise, with `id` as the tie-breaker). Every list accepts `sort` (except `GET /availability/unavailabilities`, which follows its source's date cursor): up to three comma-separated fields, each with a leading `-` for descending (`sort=-startDate,orderNumber`); the parameter's description names the sortable fields, and a field outside that list is a `400` naming it. A cursor is bound to the `limit` and the `sort` it was issued with. The time filters `createdOn` / `createdAfter` / `createdBefore` / `createdFrom` / `createdTo` and their `updated*` twins accept a bare day (read in the business timezone) or an ISO 8601 instant with offset.\n\n## Tenancy semantics (important)\n\nThe visibility of each resource depends on how Filmo models the ownership of the data. There are **two semantics**, and it pays to know them:\n\n1. **Inherited from the parent account** — applies to **contacts**, **projects**, **tags** and **custom fields**, and to reading an **order** by id. In an organization, a *billing* account (one that bills under a parent *full* account) also sees these resources of its parent account, and validates references against that same set when it writes. A full account, and a subscription outside any organization, only sees its own. There is no widening between sibling billing accounts, nor from a parent to its billing accounts.\n\n2. **Strict subscription equality** — applies to **everything else**: items, serialized items, spaces, invoices, quotes, tasks, task-types, repair-tickets, vehicles, staff, subrents, purchase-orders, contracts, project-types, the order list and availability. These resources are bounded **exactly** to the subscription that owns the API key; they are not widened to the organization. The description of each tag repeats it resource by resource.\n\nNo operation ever crosses data between different organizations.\n\nHow it shows up depending on what you are doing:\n\n- **Reading** a resource outside the tenancy of your key: `404 not_found`, identical to it not existing (it never reveals its existence).\n- **Writing** a body that **references** an identifier outside your tenancy (for example the `contactId` of an order): `400 validation_error` naming the field, and **nothing is written**. The message is the same whether the identifier does not exist or belongs to another account, so it cannot be used to probe either. It is a 400 and not a 404 because what is wrong is the body you sent, not the route you called.\n\n## Operational status vocabulary\n\nStatuses are serialized as **closed literal unions** (not numbers): a new value would be a documented additive change. The ones relevant to an integrator:\n\n**Orders.** The DTO field `status` emits the **raw status** (12 database values): `draft`, `reserved`, `prepared_partially`, `prepared`, `picked_up_partially`, `picked_up`, `returned_partially`, `returned`, `checked_in_partially`, `checked_in`, `archived`, `cancelled`. The list filter `?status=`, on the other hand, uses high-level **operational buckets** (the same view as the UI): `draft`, `reserved`, `prepared` (includes partial preparation), `in_use` (delivered / in use), `returned` (includes partial return and partial check-in), `completed` (checked in and completed) and `cancelled`.\n\n**Invoices.** `status` describes the **document lifecycle**: `draft`, `validated` (validated and numbered) or `voided`. The `?paymentStatus=` filter narrows by **payment status** with the same vocabulary the `paymentStatus` field returns: `unpaid` (nothing collected yet), `partially_paid`, `paid`, `overpaid` (collected above the total), `overdue` (past due and unpaid) or `voided` (the document is voided). The list returns exclusively documents of type invoice.\n\n**Quotes.** `status` is the document lifecycle of the active version: `draft` or `validated`. `operativeStatus` is the **commercial status**: `pending` (awaiting a reply), `confirmed` (accepted), `cancelled` (rejected / cancelled) or `superseded` (replaced by another version). The detail flattens the active version of the quote.\n\n## Rate limiting\n\nEach API key has **120 requests per minute** (fixed window, all routes). In addition, the three availability queries (`POST /api/v1/availability/check`, `POST /api/v1/staff/availability` and `POST /api/v1/vehicles/availability`) share their own quota of **30 requests per minute** (being more expensive queries), independent of the global one. Every operation publishes its quotas in the `x-rateLimit` extension of this document, and the limits are the same for every plan.\n\nEvery response that consumed quota (every response once the key is authenticated and has the scope, successful or not; a 401 and a 403 `insufficient_scope` are answered before that and carry none) carries the IETF rate-limit headers `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset` (seconds until the window resets), reflecting the tighter of the quotas the request consumed. When a limit is exceeded the response is `429 rate_limited` with `Retry-After` (seconds until the next window). Design your client to honor `Retry-After` with exponential backoff.\n\n## Idempotency (retry without duplicating)\n\nA network timeout does not tell you whether the request arrived. Blindly retrying a create makes the resource twice; not retrying leaves it never created. The optional `Idempotency-Key` header closes that gap: you choose the value (one UUID per business operation is fine) and send it on the first attempt and on every retry of **that same** operation.\n\n- **Same key + same body, within 24 h** → the stored response from the first attempt is returned, **without executing anything again**, with the `Idempotent-Replay: true` header. That is the response you are after when retrying.\n- **Same key + different body** → `422 idempotency_key_reused`, and the handler never runs. A key identifies ONE operation: reusing it for something else is almost always a client bug, and failing is safer than guessing which of the two bodies is the right one.\n- **Same key while the first attempt is still in flight** → `409 conflict`. Wait and retry; do not fire the second one in parallel.\n- **The first attempt failed before writing anything** → the key is released and the retry runs again. **It failed after the write was committed** (the response could not be built) → that error is stored and replayed like any other response: the retry does not write twice. Read the resource to see where it stands.\n- **After 24 h** the key expires and it becomes a new request again. If you need a guarantee beyond that period, use a different key and check on your side first.\n\n**Which operations accept it.** Only the ones that WRITE: the ninety-three under `/v1` (`DELETE /availability/unavailabilities/{unavailabilityId}`, `DELETE /contacts/{contactId}`, `DELETE /contacts/{contactId}/addresses/{addressId}`, `DELETE /contacts/{contactId}/related-contacts/{relatedContactId}`, `DELETE /items/{itemId}`, `DELETE /projects/{projectId}/orders/{orderId}`, `DELETE /spaces/{spaceId}`, `DELETE /staff/{staffId}`, `DELETE /tags/{tagId}`, `DELETE /tags/{tagId}/assignments`, `DELETE /tasks/{taskId}`, `DELETE /vehicles/{vehicleId}`, `PATCH /availability/unavailabilities/{unavailabilityId}`, `PATCH /collections/{collectionId}`, `PATCH /contacts/{contactId}`, `PATCH /contacts/{contactId}/addresses/{addressId}`, `PATCH /contacts/{contactId}/preferences`, `PATCH /contacts/{contactId}/related-contacts/{relatedContactId}`, `PATCH /crm/opportunities/{opportunityId}`, `PATCH /crm/opportunities/{opportunityId}/stage`, `PATCH /incidents/{incidentId}`, `PATCH /internal-services/{internalServiceId}`, `PATCH /items/{itemId}`, `PATCH /items/{itemId}/physical-properties`, `PATCH /items/{itemId}/pricing`, `PATCH /items/{itemId}/variants/{variantId}`, `PATCH /kits/{kitId}`, `PATCH /orders/{orderId}`, `PATCH /proformas/{proformaId}/status`, `PATCH /projects/{projectId}`, `PATCH /purchase-orders/{purchaseOrderId}`, `PATCH /quotes/{quoteId}/status`, `PATCH /repair-tickets/{ticketId}`, `PATCH /serialized-items/{serializedItemId}`, `PATCH /services/{serviceId}`, `PATCH /spaces/{spaceId}`, `PATCH /spaces/{spaceId}/pricing`, `PATCH /staff/{staffId}`, `PATCH /subrents/{subrentId}`, `PATCH /tasks/{taskId}`, `PATCH /treasury/payments/{paymentId}`, `PATCH /vehicles/{vehicleId}`, `POST /availability/unavailabilities`, `POST /collections`, `POST /contacts`, `POST /contacts/{contactId}/addresses`, `POST /contacts/{contactId}/related-contacts`, `POST /contracts/{contractId}/cancel`, `POST /contracts/{contractId}/sign`, `POST /contracts/{contractId}/validate`, `POST /contracts/{contractId}/void`, `POST /credit-notes/{creditNoteId}/validate`, `POST /credit-notes/{creditNoteId}/void`, `POST /crm/opportunities`, `POST /crm/opportunities/{opportunityId}/close`, `POST /crm/opportunities/{opportunityId}/links`, `POST /incidents`, `POST /incidents/{incidentId}/comments`, `POST /internal-services`, `POST /invoices/{invoiceId}/validate`, `POST /invoices/{invoiceId}/void`, `POST /items`, `POST /kits`, `POST /notes`, `POST /orders`, `POST /orders/line-items/returns`, `POST /orders/{orderId}/cancel`, `POST /orders/{orderId}/reserve`, `POST /orders/{orderId}/unreserve`, `POST /planner/assignments`, `POST /planner/assignments/remove`, `POST /projects`, `POST /projects/{projectId}/orders/{orderId}`, `POST /purchase-orders/{purchaseOrderId}/approve`, `POST /purchase-orders/{purchaseOrderId}/receive`, `POST /repair-tickets`, `POST /services`, `POST /staff`, `POST /supplier-invoices/{supplierInvoiceId}/validate`, `POST /supplier-invoices/{supplierInvoiceId}/void`, `POST /tags`, `POST /tags/{tagId}/assignments`, `POST /tasks`, `POST /treasury/payments`, `POST /treasury/payments/{paymentId}/links`, `POST /vehicles`, `POST /workflows/{workflowId}/runs`, `PUT /invoices/external/{originSystem}/{originExternalId}`, `PUT /items/{itemId}/accessories`, `PUT /items/{itemId}/alternatives`, `PUT /orders/{orderId}/archive`, `PUT /projects/{projectId}/archive`, `PUT /spaces/{spaceId}/amenities`). Reads ignore it, and so do the query-by-body calls (`/availability/check`, `/ai/ask`): they are POST because the question does not fit in a query string, not because they have side effects. Each operation that accepts it declares the parameter in its own contract, so your SDK generator already sees it.\n\n## Concurrency (optimistic locking)\n\nEvery detail read (`GET /api/v1/<resource>/{id}`) returns a strong `ETag`: a hash of the representation, so it changes whenever anything you can see changes. Send it back in the `If-Match` header of a write on that resource (PATCH, PUT, DELETE or an action such as `/reserve`) and the write is rejected with `412 precondition_failed` **before doing anything** if the resource changed since you read it; read it again and retry. The comparison and the write run under a per-resource lock, so two concurrent writes carrying the same tag end `200` / `412` exactly as they would one after the other; a write that waits more than five seconds for that lock is answered `409 conflict` and can simply be retried. `If-Match: *` only requires that the resource exists, and without the header the write always proceeds.\n Writes on resources that have no detail read yet (tags, notes, unavailabilities, collections, planner assignments, workflow runs) and the line-item returns batch, which spans several orders, do not accept `If-Match`. Expansions you request on a read (such as the stage history of an opportunity) are not part of the tag, so the tag of an expanded read still matches.\n\n## Versioning and lifecycle\n\nThe version of this specification is `info.version` (semver). Before `1.0.0` the contract was a pre-release (`1.0.0-beta`) and changed without notice. `1.0.0` is the public launch, recorded as the first release in the *Changelog* at the end of this document.\n\nFrom `1.0.0` the following policy applies, and the guardians of the repository enforce it (a breaking change without notice does not pass CI):\n\n- **Only additive changes within v1.** Additive is: a new operation; a new optional request field, filter or parameter; a new property in a response; a new value in a response union (a status, a kind); a loosened validation. They ship in any release, without prior notice, and are recorded in the changelog with the version they arrived in. Your integration **must tolerate** a property or a union value it does not know: ignore what you do not use, and do not validate responses with closed schemas that reject unknown properties.\n- **Nothing breaks without notice.** Removing or renaming an operation, a field or a parameter, changing a type, making a response property nullable, tightening a validation or changing the scope an operation requires is a breaking change. It is done in exactly two ways. **Under a new major version** (`/api/v2`), with v1 kept for at least twelve months after v2 is announced. Or **through deprecation with notice**: the operation is marked `deprecated` in this document, with `x-deprecation` naming the version that announced it, the day it takes effect, the sunset day and the replacement; every response of it carries the `Deprecation` (RFC 9745) and `Sunset` (RFC 8594) headers and a `Link` with `rel=\"deprecation\"` to this documentation; and every JSON body of it carries `meta.warnings[]` with code `deprecated`. The sunset day is at least **six months** after the day the deprecation takes effect; the operation keeps working until then and disappears on the sunset day (`404 not_found` afterwards).\n- **A field is never removed within a major version.** A field that stops making sense is marked `deprecated` in its schema and recorded in the changelog, and it is removed only in the next major.\n- **Changelog.** Every release is recorded in the *Changelog* section of this document with its version and date: what was added, what was deprecated (with its sunset day) and what was removed once its sunset passed.\n- Business-sensitive fields (costs, margins, access codes, internal tax documents, staff payroll/PII data) are **excluded by design** from the public edge and will not be added to v1.\n\n## MCP server\n\n**Every** operation in this specification — with no exceptions and no additions — is also exposed as an **MCP server** (Model Context Protocol) for AI agents, at `POST /api/v1/mcp` (Streamable HTTP transport). No number is quoted here on purpose: the catalog grows within v1 and a hand-written figure ages; the living list is `tools/list`, and this document. Each operation is a tool with a stable name (`filmo_contacts_list`, `filmo_tasks_create`, …); its `inputSchema` is derived from this very contract. Authentication is identical — the API key as bearer token — and each tool demands the scope of its endpoint. The tool catalog (`tools/list`) is public, just like this spec; execution (`tools/call`) requires a credential.\n\n## OAuth (connect an integration without pasting the key by hand)\n\nBesides the API key created in settings, the API supports an **OAuth 2.1** flow designed for remote MCP clients (the claude.ai connector and any client compatible with the MCP Authorization spec). It serves to obtain the credential in a standard, revocable way; it is **not** a second authentication system: the token it issues is a short-lived API key and travels the same way, as `Authorization: Bearer`.\n\n- **Discovery**: `GET /.well-known/oauth-authorization-server` (RFC 8414) and `GET /.well-known/oauth-protected-resource` (RFC 9728). Both public. The 401 from `/api/v1/mcp` includes `WWW-Authenticate` with `resource_metadata`, so a client discovers on its own where to authenticate.\n- **Registration**: `POST /api/v1/oauth/register` (RFC 7591). Public client: a `client_id` is returned and there is **no** `client_secret`.\n- **Authorization**: `GET /oauth/authorize` with **PKCE S256 mandatory** (`plain` is rejected). The consent screen is seen by an **administrator** of the account — the same requirement as creating a key by hand — and that is where the subscription is chosen and the permissions you do not want to grant are unchecked.\n- **Exchange**: `POST /api/v1/oauth/token` with `grant_type=authorization_code` (or `refresh_token` to rotate). The response includes `scope` with the permissions **actually** granted, which may be fewer than the ones requested.\n\nThe access token expires in 1 hour and the refresh token rotates on every use. Revoking the corresponding key in **Ajustes → API y MCP** (Settings → API and MCP) (it appears labeled as a connected integration) cuts off access instantly.\n\nThe OAuth endpoints return errors in the flat OAuth 2.1 format (`{ \"error\": \"...\", \"error_description\": \"...\" }`), not in the envelope of the rest of the API: that is what standard clients expect.\n\n## Errors\n\nErrors are **RFC 9457 problem details**, served as `application/problem+json`:\n\n```json\n{\n  \"type\": \"https://docs.filmo.io/errors/validation_error\",\n  \"title\": \"Validation error\",\n  \"status\": 400,\n  \"code\": \"validation_error\",\n  \"detail\": \"2 validation errors\",\n  \"errors\": [\n    { \"path\": \"lines[0].itemId\", \"code\": \"not_found\", \"message\": \"The itemId identifier does not exist or does not belong to this account\" },\n    { \"path\": \"endDate\", \"code\": \"must_be_after\", \"message\": \"endDate must be after startDate\" }\n  ],\n  \"requestId\": \"req_5f1c2f4e3a5b4f6d8e7a0b1c2d3e4f5a\"\n}\n```\n\n- `code` is stable and can be mapped in your client: `unauthorized`, `api_key_invalid`, `api_key_revoked`, `api_key_expired`, `api_key_owner_inactive`, `api_key_owner_not_admin`, `insufficient_scope`, `forbidden`, `addon_required`, `validation_error`, `idempotency_key_reused`, `not_found`, `conflict`, `contact_in_use`, `address_in_use`, `insufficient_stock`, `precondition_failed`, `rate_limited`, `internal_error`, `service_unavailable`. `type` is the same code as a URI and `title` its short English name; the three never change for a given code.\n- `detail` and every `errors[].message` are for people: they come in the language negotiated with the `Accept-Language` header (`es-ES` and `en-US` are guaranteed; any other supported language falls back to English) and, without the header, in the preferred language of the person who owns the API key (Spanish, `es-ES`, if they have not set one). A request with no credential, or with a key that does not exist, has no owner and always comes back in Spanish. Do **not** use them for control logic. The response says which language it used in `Content-Language`.\n- On `validation_error`, `errors[]` lists **every** offending field, not only the first: `path` in dot and bracket notation (`lines[0].itemId`, empty for the whole body) and a stable field `code` (`required`, `invalid_type`, `invalid_value`, `too_small`, `too_big`, `unknown_field`, `invalid_format`, `not_found`, `must_be_after`…).\n- On `409 contact_in_use`, `409 address_in_use` and `409 insufficient_stock`, `errors[]` says what blocks the operation: one entry per type of record that uses the contact or the address (`path` the type, `count` how many), or one per item without enough stock (`itemId`, `requested`, `available`, `shortfall`).\n- `403 insufficient_scope` names the missing scope in `requiredScope`; `402 addon_required` names the add-on in `requiredAddon`.\n- `requestId` identifies the request (it is also the `X-Request-Id` header of every response, successful or not).\n\n**Three different kinds of \"you cannot\", and it pays to tell them apart.** `403 insufficient_scope` is about the KEY: it does not carry the scope the endpoint asks for, and it is fixed by reissuing it with that scope. `403 forbidden` is about the OWNER of the key: the key is correct but its owner lacks the module, organization or administrator permission the operation demands — an administrator of the account grants it. `402 addon_required` is not about permissions but about the PLAN: the account has not contracted (or has let expire) the add-on of the module, and no role bypasses it. Sending all three to the same place sends you debugging in the wrong place two times out of three.\n\n**About the person behind the key.** An API key is issued under the authority of an **administrator** of the account — the requirement both for creating it by hand and for connecting an integration through OAuth — and everything it writes is attributed to that administrator. That condition is checked on **every request**, not only when the key is issued: if whoever created the key leaves the account or is deactivated it responds `401 api_key_owner_inactive`, and if they stop being an administrator, `401 api_key_owner_not_admin`. If your integration suddenly starts receiving one of the two, the key is fine: what changed is the role of its owner. The fix is to reissue it from an account that is still an administrator.\n\n## Changelog\n\nAll notable changes to the Filmo Public API v1 contract, newest first. Versions are the `info.version` of the OpenAPI document (semver); dates are the day the version went live. Additive changes ship without prior notice; anything else is announced here and in the responses themselves (see _Versioning and lifecycle_).\n\n### [Unreleased]\n\n### [1.0.0] - 2026-10-25\n\n#### Added\n\n- `retryAfter` on the `429 rate_limited` problem (REST and MCP): seconds to wait before retrying, the same value as the `Retry-After` header; `detail` says it too.\n- MCP tool results carry in `meta` what REST sends as headers: `meta.idempotencyKey` (the key the call ran with, yours or the one the server generated), `meta.idempotentReplay` (`true` when the result is the stored response of an earlier call with the same key) and `meta.rateLimit` (`limit`, `remaining`, `reset`).\n- MCP: `_meta[\"anthropic/requiresUserInteraction\"]: true` on the tools that cannot be undone (deletes, cancellations, voids, validations of fiscal documents, signing a contract) and on the four that must carry their own `idempotencyKey`.\n- MCP: the `WWW-Authenticate` header of the `401` of `/api/v1/mcp` carries `scope` with the read scopes, so clients ask for read access by default.\n- `GET /planner/services` rows carry `rowKind` (`summary` or `detail`): a service comes as one `summary` row (no assignee) plus one `detail` row per person or vehicle assigned, with the same `orderServiceId`. Group by `orderServiceId`; a null `staffMemberId` on the summary row does not mean uncovered.\n- Every successful response (2xx) of every operation carries an `example`: deterministic, fictitious data (RFC 2606 domains) that validates against the response schema.\n- One example response per error code (the 20 `code`s), as `components.examples.Problem_<code>` and referenced from the error responses of every operation, with the real `title` and shape of the problem.\n\n#### Changed\n\n- Error `type` URIs are now `https://docs.filmo.io/errors/<code>` (they were `https://developers.filmo.io/errors/<code>`). Branch on `code`, not on the URI.\n- Every 409 `conflict` now carries its cause in `errors[0].code`: `in_progress`, `lock_timeout` or `invalid_state`. Where `errors[].code` used to be `conflict` (unique violations, and the lines of an atomic batch that fail because their state forbids the operation) it is now `invalid_state`; a batch line that does not exist or has an invalid quantity still reports `not_found` or `validation_error`.\n- Success bodies are named schemas with an optional `meta.warnings`; write responses declare the `Idempotent-Replay` header.\n- The documentation moved to https://docs.filmo.io; in production `/api/v1/docs` redirects there.\n- MCP errors: a failed `tools/call` returns `isError: true` with the RFC 9457 problem as JSON in `content[0].text`, and no `structuredContent`. The official MCP SDKs validate `structuredContent` against the success `outputSchema` even on errors.\n- MCP `outputSchema` no longer sets `additionalProperties: false`: a field added to a response is a compatible change and does not fail validation in the client.\n- MCP annotations: `destructiveHint: true` on the validations of invoices, credit notes, contracts and supplier invoices, on `filmo_contracts_sign`, `filmo_purchase_orders_receive`, `filmo_orders_line_items_return` and `filmo_treasury_payments_create`. `filmo_ai_ask` is no longer `readOnlyHint` (each call spends AI credits) and keeps `openWorldHint`.\n- OAuth consent: only read scopes are pre-selected (the ones the client asks for, or all of them if it asks for none); write scopes, `workflows:run` and `ai:ask` always start unselected and the administrator turns them on. `scope` is optional on `/oauth/authorize`, and unknown scopes are ignored instead of failing the request.\n- OAuth in production: the issuer, the endpoints and the protected `resource` are always on `https://app.filmo.io`; `/api/v1/mcp` and the `.well-known` documents on any other production host answer `308` to it.\n- MCP server `instructions`: the essentials (safe retries, how errors arrive, dates, money, `ifMatch`) come first, within the first 2,048 characters; JSON-RPC error messages are in English.\n- Date filters (`createdOn`, `issueDateBefore`, `returnTo`…) are published as a single `type: string` with a `pattern` (a bare day `YYYY-MM-DD` or an ISO 8601 instant with offset) instead of `anyOf` of `date` and `date-time`, which some client generators could not compile. The server accepts exactly the same values.\n- The 401 and 403 responses no longer declare the `RateLimit-*` headers: they were never sent (those errors are answered before the request counts against the limit).\n- Every operation that can answer 402 for a missing add-on names it in its `x-required-addon` extension (e.g. `[\"incidence\"]`). `ProblemDetails.requiredAddon` and `AccountDto.addons` are now closed enums of add-on ids; `GET /account` only lists ids from that catalog.\n- The `path` of the `errors[]` entries of a 409 `contact_in_use` (the type of record that uses the contact: `orders`, `projects`, `quotes`, `invoices`, `proformas`, `creditNotes`, `simpleCreditNotes`, `salesReceipts`, `supplierInvoices`, `contracts`, `subrents`, `purchaseOrders`, `sepaMandates`, `receipts`, `consignments`), `address_in_use` (always `orders`) and `insufficient_stock` (`items` or `spaces`) is a closed set, published per code in the `x-path-values` extension of `ProblemDetails.errors[].path`.\n- `Idempotency-Key` is declared with `minLength: 1`. An empty key was already a 400 `validation_error` over REST; the MCP tools now reject an empty `idempotencyKey` the same way (`errors[0].path` = `idempotencyKey`) instead of ignoring it and running the write unprotected.\n\n#### Fixed\n\n- Every MCP tool result now validates with the official SDKs (`Client.callTool` in TypeScript and Python): successes with `meta.idempotencyKey` and every error used to fail with `-32602 Structured content does not match the tool's output schema`.\n- Detail reads sent with `If-None-Match` now answer `304 Not Modified` (no body, with `ETag`) when the tag is current, as the spec already declared. Until now they returned a full 200.\n- Without `Accept-Language`, the 401s of a key that exists (revoked, expired, owner inactive or not an administrator) and the 403 `insufficient_scope` came back in Spanish whatever the owner of the key preferred. They now use the preferred language of the owner, like every later error; a request with no credential or an unknown key is still Spanish.\n- `upsertExternalInvoice` documented customer and totals problems as 422; they are 400 `validation_error`, and `errors[0].path` now names the field (`contactId`, `contactTaxId`, `contactName`, `subTotal`, `taxTotal`, `total`, `lines[n].taxRate`)."},"servers":[{"url":"https://app.filmo.io","description":"Production"}],"tags":[{"name":"CRM","description":"Sales opportunities and the pipelines they move through. They are created, updated, moved between stages, closed, and linked to the quote, order or project that came out of them. Writes use optimistic locking: send the `version` you read. Requires the CRM add-on: without it the response is 402 addon_required, not 403. Strict per-subscription tenancy."},{"name":"Contacts","description":"Contacts (customers and suppliers) of the CRM. Reading and validated writing. Tenancy inherited from the parent account (see *Tenancy semantics*)."},{"name":"Items","description":"Catalog of inventory items (equipment) and the physical serialized items of each one (`/serialized-items`, filterable by `itemId`). Reading, creation and update of an item, including its physical properties, pricing, accessories, alternatives and variants. The SKU is optional on create: if omitted, the server assigns the next available one. Strict per-subscription tenancy."},{"name":"Availability","description":"Availability check of items in a date range. Idempotent (POST because of the query body)."},{"name":"Orders","description":"Rental orders, and the lines they carry. Reading, creation of an order in draft, update of its dates, contact and project, and the transitions of its lifecycle: reserve, unreserve, cancel, archive and return of line items. Lines belong to the order: they are requested with `GET /api/v1/orders/{orderId}/lines` and there is no independent collection of lines. Tenancy: reading an order by id is inherited from the parent account; the list is strict to the subscription (see *Tenancy semantics*)."},{"name":"Invoices","description":"Issued invoices: reading, and the two transitions of the document lifecycle — validate (numbers, signs and locks) and void (keeps the number). Composing an invoice remains a job for the editor. Strict per-subscription tenancy."},{"name":"Quotes","description":"Quotes (active version flattened): reading and changing the commercial status (`PATCH /api/v1/quotes/{quoteId}/status`). Confirming a version leaves the others as `superseded`. Strict per-subscription tenancy."},{"name":"Projects","description":"Projects that group orders and work. Reading, creation of a project in draft, update, and linking or unlinking an order to the project. Includes the catalog of project types (`/project-types`), useful for discovering the accepted `projectTypeId` before writing. Tenancy inherited from the parent account (see *Tenancy semantics*)."},{"name":"Tasks","description":"Tasks and schedule events. Reading and validated writing. Strict per-subscription tenancy."},{"name":"Task types","description":"Catalog of task types (system + custom). Read-only."},{"name":"Spaces","description":"Warehouses that manage stock, and rentable spaces. They are told apart by `isWarehouse`. They are read, updated, have their services and equipment replaced, and have their pricing set. The holding costs of the space are not part of the public contract. Strict per-subscription tenancy."},{"name":"Repair tickets","description":"Maintenance repair tickets: what broke and what is quoted to the customer for fixing it. The COST of the repair is not published in either direction: `unitPrice` is a sale price, not a cost. Strict per-subscription tenancy."},{"name":"Vehicles","description":"Delivery vehicle fleet, and its commitments in a date range (`POST /api/v1/vehicles/availability`, which is a query despite the method). They are created and updated from the fleet system. The cost per kilometer and the fixed cost are not part of the public contract. Strict per-subscription tenancy."},{"name":"Staff","description":"The staff, with a minimal projection for planning, and their commitments in a date range (`POST /api/v1/staff/availability`, which is a query despite the method). No contact, identity, payroll or platform access data, neither when reading nor when writing: create and patch accept ONLY the organizational part — type of engagement, collection, tags, driving license and external reference. Strict per-subscription tenancy."},{"name":"Subrents","description":"Equipment rented from other companies to cover a job: reading and updating (dates, status, notes and the link to its purchase order; the supplier price is not published). Strict per-subscription tenancy."},{"name":"Purchase orders","description":"Purchase orders to suppliers. The amounts ARE costs, because the object is a purchase; lines are not published, so the expense cannot be attributed to a specific item of a rental. They can be modified, approved and received. Strict per-subscription tenancy."},{"name":"Contracts","description":"Rental contracts, with their document and signature status: reading and the four transitions — validate, sign, void and cancel. Strict per-subscription tenancy."},{"name":"Custom fields","description":"Definitions of the custom fields of the account. Read-only: v1 reads custom fields but does not write them. Lets you identify a field and the values it accepts."},{"name":"Tags","description":"The tag vocabulary of the account, and the link between a tag and an entity. Removing a link (`DELETE /api/v1/tags/{tagId}/assignments`) does NOT delete the tag: it still exists and remains assigned to everything else."},{"name":"Kits","description":"Named groupings of items that go out together. The detail does not return the items that make up the kit: the internal read does not guarantee them. Strict per-subscription tenancy."},{"name":"Collections","description":"The tree the catalog is organized by: items, spaces, vehicles, staff and services hang from a collection. Listed with `GET /api/v1/collections`, created and updated; the identifier and the path also travel in the detail of each entity."},{"name":"Planner","description":"The board of staff and fleet services to cover in a date range, and the assignments that fill it. The identifier used to assign a service line is `orderServiceId`."},{"name":"Schedule","description":"The consolidated schedule of a range: projects, orders, tasks, internal assignments and order services. Read-only — it is a projection of those five entities, not a resource that gets written. Assignees come out by identifier and name, without their contact details."},{"name":"Supplier invoices","description":"Invoices received from suppliers: list, read by identifier, validate and void. One is reached from the treasury payment that pays it."},{"name":"Treasury","description":"Treasury accounts and the payments that go through them. The bank account number is NOT published: to reference an account, its identifier is enough. Accounts are neither created nor modified from outside; payments are."},{"name":"Credit notes","description":"Credit notes: what is returned to the customer. List, read by identifier, validate and void. The signed tax document, the tax breakdown and the lines are not published."},{"name":"Proformas","description":"Advance invoices that are not invoices yet. Reading by identifier and changing the operative status; they share the scope of invoices."},{"name":"Services","description":"Sellable lines that do not come out of inventory: staff, transport, working days. They are read, created and updated, pricing included. They do NOT emit their cost or the internal name of the service."},{"name":"Internal services","description":"Planned assignments that do not hang from an order: maintenance, transfers, training. The minimum duration is fifteen minutes."},{"name":"Incidents","description":"Broken, lost or damaged equipment, with its repair status. Requires the `incidence` add-on: without it the response is 402, not 403. Listed with `GET /api/v1/incidents` and counted by status with `GET /api/v1/incidents/status-counts`. It does not emit the cost of the repair or the internal resolution note."},{"name":"Notes","description":"Notes attached to an entity of the account. Created with `POST /api/v1/notes` and listed, for ONE entity at a time, with `GET /api/v1/notes`: there is no listing of all the notes of the account. Who wrote it is not emitted."},{"name":"Workflows","description":"Execution of the workflows of the account: `POST /api/v1/workflows/{workflowId}/runs` enqueues a run and returns its identifier and its initial status. What gets created is a RUN, not a workflow — definitions are not published, and are neither read nor written from outside. The run executes in the background and does whatever its steps say, so the `workflows:run` scope grants modifying data indirectly: it is the broadest permission in the contract. It only triggers workflows with a manual trigger and a saved version; the trigger form travels in `payload` and is validated against the frozen version. Strict per-subscription tenancy."},{"name":"AI","description":"Ask the Filmo AI about the data of your account in natural language. It NEVER writes: the engine runs without a single write tool loaded, and what it can read is decided by the permission guardrail of the key owner, table by table. It consumes AI credit of the account: without quota it responds 402."},{"name":"Account","description":"The account that made the request: name, timezone, currency, country, add-ons, trial, the API key with its scopes, the usage limits and the version of the contract. Read-only, and the first call of any integration: it replaces guessing how to interpret dates and amounts and which resources will respond 402."},{"name":"Users","description":"The people with access to the account — the ones who sign in to Filmo, not the staff — with their role, whether they administer the account, the status of their access and the staff member they are linked to. Read-only and administrators only: access and roles are granted in the app, with the consent screen in front."}],"security":[{"bearerApiKey":[]}],"externalDocs":{"description":"Filmo developer documentation","url":"https://docs.filmo.io"},"components":{"securitySchemes":{"bearerApiKey":{"type":"http","scheme":"bearer","bearerFormat":"fk_live_<random>","description":"Filmo API key as bearer token. Format `fk_live_<random>`. It is generated in Settings → API and MCP (administrators only)."}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per minute for the tightest quota this request consumed (the global one, or the additional one of the operation).","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests remaining in the current one-minute window of that quota.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until that window resets.","schema":{"type":"integer"}},"X-Request-Id":{"description":"Identifier of the request (`req_…`), also in `requestId` of every error body. Quote it when contacting support.","schema":{"type":"string"}},"ETag":{"description":"Strong entity tag of the representation (a hash of `data`). Send it back as `If-Match` on a write to be rejected with 412 if the resource changed since you read it.","schema":{"type":"string"}},"Content-Language":{"description":"Language of `detail` and `errors[].message`, negotiated from `Accept-Language` (by default, the preferred language of the owner of the API key; Spanish when no key is identified).","schema":{"type":"string"}},"Retry-After":{"description":"On 429: seconds to wait before retrying (the window reset).","schema":{"type":"integer"}},"Idempotent-Replay":{"description":"Present with the value `true` when this response is the stored one of an earlier request with the same `Idempotency-Key` and body (nothing was executed again). Absent on the first execution. A stored error is replayed too: repeating the key after a 500 returns the same 500.","schema":{"type":"string","enum":["true"]}}},"examples":{"Problem_validation_error":{"summary":"Validation error","value":{"type":"https://docs.filmo.io/errors/validation_error","title":"Validation error","status":400,"code":"validation_error","detail":"2 validation errors","requestId":"req_0b9f6c1d2e3a4f5a8b7c6d5e4f3a2b1c","errors":[{"path":"name","code":"too_small","message":"Must be at least 1 characters long"},{"path":"contactType","code":"invalid_value","message":"Value not allowed; expected company, person"}]}},"Problem_unauthorized":{"summary":"Unauthorized","value":{"type":"https://docs.filmo.io/errors/unauthorized","title":"Unauthorized","status":401,"code":"unauthorized","detail":"Missing Authorization header: Bearer <api key>","requestId":"req_0b9f6c1d2e3a4f5a8b7c6d5e4f3a2b1c"}},"Problem_api_key_invalid":{"summary":"Invalid API key","value":{"type":"https://docs.filmo.io/errors/api_key_invalid","title":"Invalid API key","status":401,"code":"api_key_invalid","detail":"The API key is not valid","requestId":"req_0b9f6c1d2e3a4f5a8b7c6d5e4f3a2b1c"}},"Problem_api_key_revoked":{"summary":"API key revoked","value":{"type":"https://docs.filmo.io/errors/api_key_revoked","title":"API key revoked","status":401,"code":"api_key_revoked","detail":"The API key has been revoked","requestId":"req_0b9f6c1d2e3a4f5a8b7c6d5e4f3a2b1c"}},"Problem_api_key_expired":{"summary":"API key expired","value":{"type":"https://docs.filmo.io/errors/api_key_expired","title":"API key expired","status":401,"code":"api_key_expired","detail":"The API key has expired","requestId":"req_0b9f6c1d2e3a4f5a8b7c6d5e4f3a2b1c"}},"Problem_api_key_owner_inactive":{"summary":"API key owner inactive","value":{"type":"https://docs.filmo.io/errors/api_key_owner_inactive","title":"API key owner inactive","status":401,"code":"api_key_owner_inactive","detail":"The user who created the API key is no longer active in the account","requestId":"req_0b9f6c1d2e3a4f5a8b7c6d5e4f3a2b1c"}},"Problem_api_key_owner_not_admin":{"summary":"API key owner is not an administrator","value":{"type":"https://docs.filmo.io/errors/api_key_owner_not_admin","title":"API key owner is not an administrator","status":401,"code":"api_key_owner_not_admin","detail":"The user who created the API key is no longer an administrator of the account","requestId":"req_0b9f6c1d2e3a4f5a8b7c6d5e4f3a2b1c"}},"Problem_insufficient_scope":{"summary":"Insufficient scope","value":{"type":"https://docs.filmo.io/errors/insufficient_scope","title":"Insufficient scope","status":403,"code":"insufficient_scope","detail":"The API key does not have the required scope (orders:write)","requestId":"req_0b9f6c1d2e3a4f5a8b7c6d5e4f3a2b1c","requiredScope":"orders:write"}},"Problem_forbidden":{"summary":"Forbidden","value":{"type":"https://docs.filmo.io/errors/forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"You are not allowed to perform this operation","requestId":"req_0b9f6c1d2e3a4f5a8b7c6d5e4f3a2b1c"}},"Problem_rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://docs.filmo.io/errors/rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Rate limit exceeded: retry in 30 seconds","requestId":"req_0b9f6c1d2e3a4f5a8b7c6d5e4f3a2b1c","retryAfter":30}},"Problem_internal_error":{"summary":"Internal error","value":{"type":"https://docs.filmo.io/errors/internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Internal error","requestId":"req_0b9f6c1d2e3a4f5a8b7c6d5e4f3a2b1c"}},"Problem_not_found":{"summary":"Not found","value":{"type":"https://docs.filmo.io/errors/not_found","title":"Not found","status":404,"code":"not_found","detail":"Resource not found","requestId":"req_0b9f6c1d2e3a4f5a8b7c6d5e4f3a2b1c"}},"Problem_conflict":{"summary":"Conflict","value":{"type":"https://docs.filmo.io/errors/conflict","title":"Conflict","status":409,"code":"conflict","detail":"The current state of the resource does not allow the operation","requestId":"req_0b9f6c1d2e3a4f5a8b7c6d5e4f3a2b1c","errors":[{"path":"","code":"invalid_state","message":"The current state of the resource does not allow the operation"}]}},"Problem_precondition_failed":{"summary":"Precondition failed","value":{"type":"https://docs.filmo.io/errors/precondition_failed","title":"Precondition failed","status":412,"code":"precondition_failed","detail":"The resource changed since you read it: read it again and retry","requestId":"req_0b9f6c1d2e3a4f5a8b7c6d5e4f3a2b1c"}},"Problem_idempotency_key_reused":{"summary":"Idempotency-Key reused","value":{"type":"https://docs.filmo.io/errors/idempotency_key_reused","title":"Idempotency-Key reused","status":422,"code":"idempotency_key_reused","detail":"The Idempotency-Key header was already used with a different body","requestId":"req_0b9f6c1d2e3a4f5a8b7c6d5e4f3a2b1c"}},"Problem_contact_in_use":{"summary":"Contact in use","value":{"type":"https://docs.filmo.io/errors/contact_in_use","title":"Contact in use","status":409,"code":"contact_in_use","detail":"The contact is used by orders, projects, documents or payments and cannot be deleted: archive it instead (status: archived). The count per type is in errors","requestId":"req_0b9f6c1d2e3a4f5a8b7c6d5e4f3a2b1c","errors":[{"path":"orders","code":"in_use","message":"Used by 3 records of this type","count":3},{"path":"quotes","code":"in_use","message":"Used by 1 record of this type","count":1}]}},"Problem_address_in_use":{"summary":"Address in use","value":{"type":"https://docs.filmo.io/errors/address_in_use","title":"Address in use","status":409,"code":"address_in_use","detail":"The address is the billing or shipping address of 2 orders: change it on them before deleting it","requestId":"req_0b9f6c1d2e3a4f5a8b7c6d5e4f3a2b1c","errors":[{"path":"orders","code":"in_use","message":"Used by 2 records of this type","count":2}]}},"Problem_addon_required":{"summary":"Add-on required","value":{"type":"https://docs.filmo.io/errors/addon_required","title":"Add-on required","status":402,"code":"addon_required","detail":"Your plan does not include the add-on this operation requires","requestId":"req_0b9f6c1d2e3a4f5a8b7c6d5e4f3a2b1c","requiredAddon":"incidence"}},"Problem_service_unavailable":{"summary":"Service unavailable","value":{"type":"https://docs.filmo.io/errors/service_unavailable","title":"Service unavailable","status":503,"code":"service_unavailable","detail":"This feature is not available for the account right now","requestId":"req_0b9f6c1d2e3a4f5a8b7c6d5e4f3a2b1c"}},"Problem_insufficient_stock":{"summary":"Insufficient stock","value":{"type":"https://docs.filmo.io/errors/insufficient_stock","title":"Insufficient stock","status":409,"code":"insufficient_stock","detail":"1 item does not have enough stock for the dates of the order; nothing was reserved. The detail is in errors","requestId":"req_0b9f6c1d2e3a4f5a8b7c6d5e4f3a2b1c","errors":[{"path":"items","code":"insufficient_stock","message":"Short by 2 of 5 units for the dates of the order","itemId":"itm_9f3a2b","requested":5,"available":3,"shortfall":2}]}},"ProblemVariant_order_not_reservable":{"summary":"Conflict","value":{"type":"https://docs.filmo.io/errors/conflict","title":"Conflict","status":409,"code":"conflict","detail":"An order with status picked_up cannot be reserved","requestId":"req_0b9f6c1d2e3a4f5a8b7c6d5e4f3a2b1c","errors":[{"path":"","code":"invalid_state","message":"An order with status picked_up cannot be reserved"}]}}},"schemas":{"Pagination":{"type":"object","properties":{"nextCursor":{"type":["string","null"],"description":"Opaque cursor of the next page; null when there are no more results. Pass it as `cursor` in the next request."},"hasMore":{"type":"boolean","description":"Whether more results exist beyond this page."},"total":{"type":"integer","minimum":0,"description":"Number of results matching the filters across all pages. Present only when the request sets `includeTotal=true`."}},"required":["nextCursor","hasMore"],"description":"Opaque-cursor pagination metadata."},"ProblemDetails":{"type":"object","properties":{"type":{"type":"string","description":"URI that identifies the problem type: the documentation page of the code."},"title":{"type":"string","description":"Short, stable, English name of the problem type."},"status":{"type":"integer","description":"HTTP status code of the response."},"code":{"type":"string","enum":["unauthorized","api_key_invalid","api_key_revoked","api_key_expired","api_key_owner_inactive","api_key_owner_not_admin","insufficient_scope","forbidden","addon_required","validation_error","idempotency_key_reused","not_found","conflict","contact_in_use","address_in_use","insufficient_stock","precondition_failed","rate_limited","internal_error","service_unavailable"],"description":"Stable error code, suitable for control flow in the client."},"detail":{"type":"string","description":"Explanation of this occurrence, in the language negotiated with `Accept-Language` (by default, the preferred language of the owner of the API key; Spanish when no key is identified). Do not use it for control flow."},"requestId":{"type":"string","description":"Identifier of the request, also sent in the `X-Request-Id` header. Quote it when contacting support."},"errors":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string","description":"Path of the offending field in dot and bracket notation (`lines[0].itemId`); empty for the whole body. On `contact_in_use`, `address_in_use` and `insufficient_stock` it is one of a closed set, listed by code in `x-path-values`: the type of record that uses the contact or the address, or the kind of resource that is short (`items` or `spaces`).","x-path-values":{"contact_in_use":["orders","projects","quotes","invoices","proformas","creditNotes","simpleCreditNotes","salesReceipts","supplierInvoices","contracts","subrents","purchaseOrders","sepaMandates","receipts","consignments"],"address_in_use":["orders"],"insufficient_stock":["items","spaces"]}},"code":{"type":"string","description":"Stable code of the field error (`required`, `must_not_be_null`, `invalid_type`, `invalid_value`, `too_small`, `too_big`, `unknown_field`, `invalid_format`, `not_found`, `must_be_after`…). On a 409 `conflict` it says the cause: `in_progress` (another request with the same `Idempotency-Key` is still running), `lock_timeout` (another conditional write held the resource for more than five seconds) or `invalid_state` (the state of the resource forbids the operation)."},"message":{"type":"string","description":"Localized explanation, in the negotiated language."},"count":{"type":"integer","description":"On `contact_in_use` and `address_in_use`: how many records of the type named by `path` use it."},"itemId":{"type":"string","description":"On `insufficient_stock`: the item, or the space when `path` is `spaces`, that is short."},"requested":{"type":"number","description":"On `insufficient_stock`: units the order needs."},"available":{"type":"number","description":"On `insufficient_stock`: units available for the dates of the order."},"shortfall":{"type":"number","description":"On `insufficient_stock`: units missing (`requested` − `available`)."}},"required":["path","code","message"],"description":"One error of the request: a field that failed validation, or what blocks the operation (`contact_in_use`, `address_in_use`, `insufficient_stock`). The response carries all of them, not only the first."},"description":"Every validation error found, on `validation_error`; what blocks the operation, on `contact_in_use`, `address_in_use` and `insufficient_stock`."},"requiredScope":{"type":"string","description":"On `insufficient_scope`: the scope the API key needs."},"requiredAddon":{"type":"string","enum":["qr-codes","incidence","purchases","activity-log","custom-fields","profitability","web-builder","crm","consignments","email-calendar","sales-documents","internal-bookings","internal-communication","advanced-user-permissions"],"description":"On `addon_required`: the id of the add-on the account plan needs (the ids `GET /account` lists in `addons`)."},"retryAfter":{"type":"integer","description":"On `rate_limited`: seconds to wait before retrying, the same value as the `Retry-After` header."}},"required":["type","title","status","code","detail","requestId"],"description":"Error body of API v1: RFC 9457 problem details, served as `application/problem+json`."},"ApiWarning":{"type":"object","properties":{"code":{"type":"string","enum":["deprecated"],"description":"Stable warning code."},"message":{"type":"string","description":"For people: what is deprecated, until when, and what to use."},"sunset":{"type":"string","description":"Day (YYYY-MM-DD) the operation stops being served."},"replacement":{"type":["string","null"],"description":"`operationId` of the operation to use instead, or null if there is none."},"link":{"type":"string","description":"Where the deprecation is documented (the changelog)."}},"required":["code","message","sunset","replacement","link"],"additionalProperties":false,"description":"A lifecycle warning attached to the response of a deprecated operation."},"ResponseMeta":{"type":"object","properties":{"warnings":{"type":"array","items":{"$ref":"#/components/schemas/ApiWarning"},"description":"Lifecycle warnings; present only when the operation is deprecated."}},"description":"Additional information about the response."},"ContactDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the contact."},"name":{"type":"string","description":"Contact name (person or company)."},"contactType":{"type":"string","enum":["person","company"],"description":"Contact type: person (individual) or company (business)."},"role":{"type":"string","enum":["client","provider","lead","debtor","creditor","student","teacher","unspecified"],"description":"Contact role: client, provider, lead, debtor, creditor, student, teacher or unspecified."},"status":{"type":"string","enum":["active","inactive","archived"],"description":"Contact status: active (operational), inactive (deactivated) or archived (closed, kept for historical records)."},"nif":{"type":["string","null"],"description":"NIF/CIF or tax identification number; null if not recorded."},"commercialName":{"type":["string","null"],"description":"Trade name; null if it matches the name or is not recorded."},"position":{"type":["string","null"],"description":"Job title or position of the contact person; null if not recorded."},"contactNumber":{"type":["string","null"],"description":"Contact number assigned by the account (internal reference); null if not recorded."},"emails":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Internal identifier of the email within the contact."},"label":{"type":["string","null"],"description":"Descriptive label of the email; null if it has none."},"email":{"type":"string","description":"Email address."},"isPrimary":{"type":"boolean","description":"Whether this is the primary email of the contact."}},"required":["id","label","email","isPrimary"],"additionalProperties":false},"description":"List of email addresses of the contact."},"billingEmail":{"type":["string","null"],"description":"Dedicated billing email; null means the primary email is used."},"phoneNumbers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Internal identifier of the phone number within the contact."},"label":{"type":["string","null"],"description":"Descriptive label of the phone number; null if it has none."},"number":{"type":"string","description":"Phone number."},"countryCode":{"type":["string","null"],"description":"International country calling code (e.g. \"+34\"); null if not recorded."},"isPrimary":{"type":"boolean","description":"Whether this is the primary phone number of the contact."}},"required":["id","label","number","countryCode","isPrimary"],"additionalProperties":false},"description":"List of phone numbers of the contact."},"websites":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Internal identifier of the website within the contact."},"label":{"type":["string","null"],"description":"Descriptive label of the website; null if it has none."},"url":{"type":"string","description":"Website URL."}},"required":["id","label","url"],"additionalProperties":false},"description":"List of websites of the contact."},"addresses":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Internal identifier of the address within the contact."},"label":{"type":["string","null"],"description":"Descriptive label of the address; null if it has none."},"addressLine1":{"type":["string","null"],"description":"First line of the address; null if not recorded."},"addressLine2":{"type":["string","null"],"description":"Second line of the address; null if not recorded."},"city":{"type":["string","null"],"description":"City; null if not recorded."},"province":{"type":["string","null"],"description":"Province or region; null if not recorded."},"postcode":{"type":["string","null"],"description":"Postcode; null if not recorded."},"country":{"type":["string","null"],"description":"Country; null if not recorded."},"isMain":{"type":"boolean","description":"Whether this is the main address of the contact."}},"required":["id","label","addressLine1","addressLine2","city","province","postcode","country","isMain"],"additionalProperties":false},"description":"List of addresses of the contact."},"folder":{"type":["string","null"],"description":"Folder or organizational grouping; null if the contact is not classified."},"discountPercentage":{"type":["number","null"],"description":"General discount percentage of the contact (0-100); null if no discount is configured."},"preferredLanguage":{"type":["string","null"],"description":"Preferred language of the contact; null if not recorded."},"currency":{"type":["string","null"],"description":"Default currency of the contact as an ISO 4217 code; null if not recorded."},"paymentMethod":{"type":["object","null"],"properties":{"type":{"type":"string","enum":["bank_transfer","card","cash","other","sepa_direct_debit"],"description":"Payment method type: bank_transfer, card, cash, sepa_direct_debit or other."},"customValue":{"type":["string","null"],"description":"Free-text detail when the type is \"other\" (for example a method recorded before it was configured); null otherwise."}},"required":["type","customValue"],"additionalProperties":false,"description":"Preferred payment method of the contact; null if not configured."},"paymentDays":{"type":["array","null"],"items":{"type":"integer"},"description":"Days of the month on which the contact makes payments; null if not configured."},"expirationDays":{"type":["integer","null"],"description":"Default due days for the invoices of the contact; null if not configured."},"subscribedToMarketing":{"type":"boolean","description":"Whether the contact is subscribed to marketing communications."},"isAppUser":{"type":"boolean","description":"Whether the contact has access to the app."},"customFields":{"type":"object","additionalProperties":{},"description":"Custom field values by custom field identifier; the definitions are in /api/v1/custom-fields."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 with offset."},"updatedAt":{"type":"string","format":"date-time","description":"Last update date in ISO 8601 with offset."}},"required":["id","name","contactType","role","status","nif","commercialName","position","contactNumber","emails","billingEmail","phoneNumbers","websites","addresses","folder","discountPercentage","preferredLanguage","currency","paymentMethod","paymentDays","expirationDays","subscribedToMarketing","isAppUser","customFields","createdAt","updatedAt"],"additionalProperties":false,"description":"The contact, as returned by the API."},"ContactList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ContactDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of contact records in `data`, with its `pagination`."},"ContactDetailDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the contact."},"name":{"type":"string","description":"Contact name (person or company)."},"contactType":{"type":"string","enum":["person","company"],"description":"Contact type: person (individual) or company (business)."},"role":{"type":"string","enum":["client","provider","lead","debtor","creditor","student","teacher","unspecified"],"description":"Contact role: client, provider, lead, debtor, creditor, student, teacher or unspecified."},"status":{"type":"string","enum":["active","inactive","archived"],"description":"Contact status: active (operational), inactive (deactivated) or archived (closed, kept for historical records)."},"nif":{"type":["string","null"],"description":"NIF/CIF or tax identification number; null if not recorded."},"commercialName":{"type":["string","null"],"description":"Trade name; null if it matches the name or is not recorded."},"position":{"type":["string","null"],"description":"Job title or position of the contact person; null if not recorded."},"contactNumber":{"type":["string","null"],"description":"Contact number assigned by the account (internal reference); null if not recorded."},"emails":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Internal identifier of the email within the contact."},"label":{"type":["string","null"],"description":"Descriptive label of the email; null if it has none."},"email":{"type":"string","description":"Email address."},"isPrimary":{"type":"boolean","description":"Whether this is the primary email of the contact."}},"required":["id","label","email","isPrimary"],"additionalProperties":false},"description":"List of email addresses of the contact."},"billingEmail":{"type":["string","null"],"description":"Dedicated billing email; null means the primary email is used."},"phoneNumbers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Internal identifier of the phone number within the contact."},"label":{"type":["string","null"],"description":"Descriptive label of the phone number; null if it has none."},"number":{"type":"string","description":"Phone number."},"countryCode":{"type":["string","null"],"description":"International country calling code (e.g. \"+34\"); null if not recorded."},"isPrimary":{"type":"boolean","description":"Whether this is the primary phone number of the contact."}},"required":["id","label","number","countryCode","isPrimary"],"additionalProperties":false},"description":"List of phone numbers of the contact."},"websites":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Internal identifier of the website within the contact."},"label":{"type":["string","null"],"description":"Descriptive label of the website; null if it has none."},"url":{"type":"string","description":"Website URL."}},"required":["id","label","url"],"additionalProperties":false},"description":"List of websites of the contact."},"addresses":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Internal identifier of the address within the contact."},"label":{"type":["string","null"],"description":"Descriptive label of the address; null if it has none."},"addressLine1":{"type":["string","null"],"description":"First line of the address; null if not recorded."},"addressLine2":{"type":["string","null"],"description":"Second line of the address; null if not recorded."},"city":{"type":["string","null"],"description":"City; null if not recorded."},"province":{"type":["string","null"],"description":"Province or region; null if not recorded."},"postcode":{"type":["string","null"],"description":"Postcode; null if not recorded."},"country":{"type":["string","null"],"description":"Country; null if not recorded."},"isMain":{"type":"boolean","description":"Whether this is the main address of the contact."}},"required":["id","label","addressLine1","addressLine2","city","province","postcode","country","isMain"],"additionalProperties":false},"description":"List of addresses of the contact."},"folder":{"type":["string","null"],"description":"Folder or organizational grouping; null if the contact is not classified."},"discountPercentage":{"type":["number","null"],"description":"General discount percentage of the contact (0-100); null if no discount is configured."},"preferredLanguage":{"type":["string","null"],"description":"Preferred language of the contact; null if not recorded."},"currency":{"type":["string","null"],"description":"Default currency of the contact as an ISO 4217 code; null if not recorded."},"paymentMethod":{"type":["object","null"],"properties":{"type":{"type":"string","enum":["bank_transfer","card","cash","other","sepa_direct_debit"],"description":"Payment method type: bank_transfer, card, cash, sepa_direct_debit or other."},"customValue":{"type":["string","null"],"description":"Free-text detail when the type is \"other\" (for example a method recorded before it was configured); null otherwise."}},"required":["type","customValue"],"additionalProperties":false,"description":"Preferred payment method of the contact; null if not configured."},"paymentDays":{"type":["array","null"],"items":{"type":"integer"},"description":"Days of the month on which the contact makes payments; null if not configured."},"expirationDays":{"type":["integer","null"],"description":"Default due days for the invoices of the contact; null if not configured."},"subscribedToMarketing":{"type":"boolean","description":"Whether the contact is subscribed to marketing communications."},"isAppUser":{"type":"boolean","description":"Whether the contact has access to the app."},"customFields":{"type":"object","additionalProperties":{},"description":"Custom field values by custom field identifier; the definitions are in /api/v1/custom-fields."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 with offset."},"updatedAt":{"type":"string","format":"date-time","description":"Last update date in ISO 8601 with offset."},"relatedContacts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the related contact."},"name":{"type":"string","description":"Name of the related contact."},"commercialName":{"type":["string","null"],"description":"Trade name of the related contact; null if not recorded."},"contactType":{"type":"string","enum":["person","company"],"description":"Type of the related contact: person or company."},"role":{"type":"string","enum":["client","provider","lead","debtor","creditor","student","teacher","unspecified"],"description":"Role of the related contact."},"status":{"type":"string","enum":["active","inactive","archived"],"description":"Status of the related contact: active, inactive or archived."},"relationRole":{"type":["string","null"],"description":"Role of the relationship between the two contacts (e.g. \"employee of\"); null if not recorded."}},"required":["id","name","commercialName","contactType","role","status","relationRole"],"additionalProperties":false},"description":"Contacts related to this contact (e.g. people of a company)."}},"required":["id","name","contactType","role","status","nif","commercialName","position","contactNumber","emails","billingEmail","phoneNumbers","websites","addresses","folder","discountPercentage","preferredLanguage","currency","paymentMethod","paymentDays","expirationDays","subscribedToMarketing","isAppUser","customFields","createdAt","updatedAt","relatedContacts"],"additionalProperties":false,"description":"The contact in full, as returned by the API."},"ContactDetailResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ContactDetailDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the contact detail in `data`."},"ContactCreateBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200,"description":"Contact name (person or company). Required."},"contactType":{"type":"string","enum":["person","company"],"description":"Contact type: person (individual) or company (business)."},"role":{"type":"string","enum":["client","provider","lead","debtor","creditor","student","teacher","unspecified"],"description":"Contact role: client, provider, lead, debtor, creditor, student, teacher or unspecified."},"nif":{"type":"string","maxLength":20,"description":"NIF/CIF or tax identification number of the contact."},"commercialName":{"type":"string","maxLength":200,"description":"Trade name, if it differs from the legal name."},"position":{"type":"string","maxLength":200,"description":"Job title or position of the contact person."},"email":{"type":"string","maxLength":200,"format":"email","description":"Contact email address; the format is validated."},"phone":{"type":"string","maxLength":50,"description":"Contact phone number."},"addressLine1":{"type":"string","maxLength":300,"description":"First line of the address (street and number)."},"addressLine2":{"type":"string","maxLength":300,"description":"Second line of the address (floor, door, etc.)."},"city":{"type":"string","maxLength":200,"description":"City of the address."},"province":{"type":"string","maxLength":200,"description":"Province or region of the address."},"postcode":{"type":"string","maxLength":20,"description":"Postcode of the address."},"country":{"type":"string","maxLength":10,"description":"Country of the address (code or short name)."},"folder":{"type":"string","maxLength":200,"description":"Folder or organizational grouping of the contact."},"contactNumber":{"type":"string","maxLength":50,"description":"Contact number assigned by the account (internal reference)."},"preferredLanguage":{"type":"string","enum":["es-ES","en-US","fr-FR","ca-ES","de-DE","pl-PL"],"description":"Preferred language of the contact for communications and documents."},"currency":{"type":"string","minLength":3,"maxLength":3,"description":"Default currency of the contact as a 3-letter ISO 4217 code (e.g. \"EUR\")."},"subscribedToMarketing":{"type":"boolean","description":"Whether the contact is subscribed to marketing communications."}},"required":["name"],"additionalProperties":false,"description":"Body of the request that creates this contact."},"ContactUpdateBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200,"description":"Contact name (person or company)."},"contactType":{"type":"string","enum":["person","company"],"description":"Contact type: person (individual) or company (business)."},"role":{"type":"string","enum":["client","provider","lead","debtor","creditor","student","teacher","unspecified"],"description":"Contact role: client, provider, lead, debtor, creditor, student, teacher or unspecified."},"status":{"type":"string","enum":["active","inactive","archived"],"description":"Contact status: active (operational), inactive (deactivated) or archived (closed, kept for historical records)."},"nif":{"type":["string","null"],"maxLength":20,"description":"NIF/CIF or tax identification number; null clears it (\"\" is normalized to null too)."},"commercialName":{"type":["string","null"],"maxLength":200,"description":"Trade name; null clears it."},"position":{"type":["string","null"],"maxLength":200,"description":"Job title or position; null clears it."},"emails":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string","maxLength":200,"format":"email","description":"Email address; the format is validated."},"label":{"type":"string","maxLength":100,"description":"Descriptive label of the email (e.g. \"Personal\", \"Billing\")."},"isPrimary":{"type":"boolean","description":"Marks this email as the primary one for the contact."}},"required":["email"],"additionalProperties":false},"maxItems":20,"description":"List of email addresses that REPLACES the existing list entirely (max 20). Internal ids are generated by the server."},"phoneNumbers":{"type":"array","items":{"type":"object","properties":{"number":{"type":"string","minLength":1,"maxLength":50,"description":"Phone number."},"label":{"type":"string","maxLength":100,"description":"Descriptive label of the phone number (e.g. \"Mobile\", \"Office\")."},"countryCode":{"type":"string","maxLength":10,"description":"International country calling code (e.g. \"+34\")."},"isPrimary":{"type":"boolean","description":"Marks this phone number as the primary one for the contact."}},"required":["number"],"additionalProperties":false},"maxItems":20,"description":"List of phone numbers that REPLACES the existing list entirely (max 20). Internal ids are generated by the server."},"websites":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","maxLength":300,"format":"uri","description":"Website URL; the format is validated."},"label":{"type":"string","maxLength":100,"description":"Descriptive label of the website (e.g. \"Corporate website\", \"LinkedIn\")."}},"required":["url"],"additionalProperties":false},"maxItems":20,"description":"List of websites that REPLACES the existing list entirely (max 20). Internal ids are generated by the server."},"addresses":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1,"description":"Identifier of an existing address to keep it; omit it to add a new one."},"label":{"type":"string","maxLength":100,"description":"Descriptive label of the address (e.g. \"Billing\", \"Shipping\")."},"addressLine1":{"type":"string","minLength":1,"maxLength":300,"description":"First line of the address (street and number). Required."},"addressLine2":{"type":"string","maxLength":300,"description":"Second line of the address (floor, door, etc.)."},"city":{"type":"string","maxLength":200,"description":"City of the address."},"province":{"type":"string","maxLength":200,"description":"Province or region of the address."},"postcode":{"type":"string","maxLength":20,"description":"Postcode of the address."},"country":{"type":"string","maxLength":10,"description":"Country of the address (code or short name)."},"isMain":{"type":"boolean","description":"Marks this address as the main one for the contact."}},"required":["addressLine1"],"additionalProperties":false},"maxItems":20,"description":"List of addresses that REPLACES the existing list entirely (max 20). Send the id of each existing address you want to keep; addresses without id are created with a new one. An id that is not an address of this contact responds 400. Leaving out an address that an order uses as its billing or shipping address responds 409 `address_in_use` and nothing is changed."},"folder":{"type":["string","null"],"maxLength":200,"description":"Folder or organizational grouping; null clears it."},"contactNumber":{"type":["string","null"],"maxLength":50,"description":"Contact number (internal reference); null clears it."},"discountPercentage":{"type":["number","null"],"minimum":0,"maximum":100,"description":"General discount percentage of the contact (0-100); null clears it."},"subscribedToMarketing":{"type":"boolean","description":"Whether the contact is subscribed to marketing communications."}},"additionalProperties":false,"description":"Body of the request that updates this contact."},"ContactPreferencesBody":{"type":"object","properties":{"preferredLanguage":{"type":["string","null"],"enum":["es-ES","en-US","fr-FR","ca-ES","de-DE","pl-PL",null],"description":"Language of the documents issued to the contact, e.g. \"es-ES\"; null clears it."},"currency":{"type":["string","null"],"minLength":3,"maxLength":3,"description":"Default currency, as a 3-letter ISO 4217 code (e.g. \"EUR\"); null clears it."},"billingEmail":{"type":["string","null"],"format":"email","description":"Email address the invoices are sent to; null clears it."},"paymentMethod":{"type":["object","null"],"properties":{"type":{"type":"string","enum":["bank_transfer","card","cash","other"],"description":"Agreed payment method, in the same vocabulary the contact returns: bank_transfer, card, cash or other. Direct debit is a configured method of the account: assign it through paymentMethodIds."},"customValue":{"type":"string","description":"Free-text detail when the type is \"other\"."}},"required":["type"],"additionalProperties":false,"description":"Payment method agreed with the contact; null clears it."},"paymentMethodIds":{"type":"array","items":{"type":"string"},"description":"Payment methods configured in the account that this contact accepts."},"primaryPaymentMethodId":{"type":["string","null"],"description":"Which of them is the primary one; null clears it."},"paymentDays":{"type":["array","null"],"items":{"type":"integer","minimum":1,"maximum":31},"description":"Days of the month on which the contact pays. Replaces the whole list; null clears it."},"expirationDays":{"type":["integer","null"],"minimum":0,"description":"Due days for the invoices of the contact, as a whole number of days; null uses the account default."},"discountSettings":{"type":"object","properties":{"percentage":{"type":"number","minimum":0,"maximum":100,"description":"Usual discount, as a percentage (0-100)."}},"required":["percentage"],"additionalProperties":false,"description":"Discount applied to the contact by default."},"eInvoiceFields":{"type":["object","null"],"properties":{"accountingOffice":{"type":"string","description":"Accounting office (FACe)."},"managementBody":{"type":"string","description":"Management body (FACe)."},"processingUnit":{"type":"string","description":"Processing unit (FACe)."},"proposingBody":{"type":"string","description":"Proposing body (FACe)."}},"additionalProperties":false,"description":"Electronic invoicing codes for public administration."}},"additionalProperties":false,"description":"Body of the request that updates the commercial preferences of a contact: language, currency, billing email, payment methods and terms, discounts and e-invoicing fields. Only the fields sent change."},"ContactAddressCreateBody":{"type":"object","properties":{"addressLine1":{"type":"string","minLength":1,"description":"Address line 1. Required."},"label":{"type":"string","description":"Descriptive label, e.g. \"Billing\", \"Warehouse\"."},"addressLine2":{"type":"string","description":"Address line 2."},"city":{"type":"string","description":"City."},"province":{"type":"string","description":"Province."},"postcode":{"type":"string","description":"Postcode."},"country":{"type":"string","description":"Country."},"isMain":{"type":"boolean","description":"true makes it the main address and demotes the previous one."}},"required":["addressLine1"],"additionalProperties":false,"description":"Body of the request that creates this contact address."},"ContactAddressUpdateBody":{"type":"object","properties":{"addressLine1":{"type":"string","minLength":1,"description":"Address line 1."},"label":{"type":["string","null"],"description":"Descriptive label; null clears it."},"addressLine2":{"type":["string","null"],"description":"Address line 2; null clears it."},"city":{"type":["string","null"],"description":"City; null clears it."},"province":{"type":["string","null"],"description":"Province; null clears it."},"postcode":{"type":["string","null"],"description":"Postcode; null clears it."},"country":{"type":["string","null"],"description":"Country; null clears it."},"isMain":{"type":"boolean","description":"true makes it the main address and demotes the previous one."}},"additionalProperties":false,"description":"Body of the request that updates this contact address."},"RelatedContactDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the related contact."},"name":{"type":"string","description":"Name of the related contact."},"commercialName":{"type":["string","null"],"description":"Trade name of the related contact; null if not recorded."},"contactType":{"type":"string","enum":["person","company"],"description":"Type of the related contact: person or company."},"role":{"type":"string","enum":["client","provider","lead","debtor","creditor","student","teacher","unspecified"],"description":"Role of the related contact."},"status":{"type":"string","enum":["active","inactive","archived"],"description":"Status of the related contact: active, inactive or archived."},"relationRole":{"type":["string","null"],"description":"Role of the relationship between the two contacts (e.g. \"employee of\"); null if not recorded."}},"required":["id","name","commercialName","contactType","role","status","relationRole"],"additionalProperties":false,"description":"The related contact, as returned by the API."},"RelatedContactItems":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/RelatedContactDto"}},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the related contact records in `data`."},"RelatedContactCreateBody":{"type":"object","properties":{"relationRole":{"type":"string","maxLength":200,"description":"Role of the relationship, e.g. \"Director\", \"Contact person\". Required when a company relates a person; not allowed when a person relates a company."},"relatedContactId":{"type":"string","minLength":1,"description":"Contact to relate to."}},"required":["relatedContactId"],"additionalProperties":false,"description":"Body of the request that creates this related contact."},"RelatedContactUpdateBody":{"type":"object","properties":{"relationRole":{"type":"string","maxLength":200,"description":"New role of the relationship. Send an empty string to clear it."}},"required":["relationRole"],"additionalProperties":false,"description":"Body of the request that updates this related contact."},"ItemDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the item."},"name":{"type":"string","description":"Item name."},"sku":{"type":["string","null"],"description":"SKU reference of the item; null if not recorded."},"description":{"type":["string","null"],"description":"Item description; null if not recorded."},"orderInfo":{"type":["string","null"],"description":"Additional information for the order (preparation/delivery notes); null if not recorded."},"ean":{"type":["string","null"],"description":"EAN/barcode; null if not recorded."},"itemType":{"type":"string","enum":["fixed","variant"],"description":"Item type: fixed (simple item) or variant (item with variants)."},"stockCalculationMethod":{"type":"string","enum":["bulk","serialized"],"description":"Stock calculation method: bulk (in bulk, by quantity) or serialized (by serialized items)."},"collectionId":{"type":["string","null"],"description":"Identifier of the collection it belongs to; null if it is in none."},"collectionName":{"type":["string","null"],"description":"Name of the collection it belongs to; null if it is in none."},"images":{"type":"array","items":{"type":"string"},"description":"URLs of the item images."},"salePrice":{"type":["string","null"],"pattern":"^-?\\d+\\.\\d{2}$","description":"Sale price as a decimal string \"1234.50\" (ROUND_HALF_UP); null if it has none."},"depositValue":{"type":["string","null"],"pattern":"^-?\\d+\\.\\d{2}$","description":"Deposit amount as a decimal string \"1234.50\" (ROUND_HALF_UP); null if it has none."},"minStock":{"type":["number","null"],"description":"Minimum stock configured for alerts; null if not configured."},"serializedItemsCount":{"type":"number","description":"Number of serialized items registered for the item."},"pricingSettings":{"type":["object","null"],"properties":{"type":{"type":["string","null"],"enum":["periodPrice","fixedPrice","pricingStructure",null],"description":"Pricing mode: periodPrice (price per period), fixedPrice (fixed price) or pricingStructure (pricing structure); null if the item has none configured."},"price":{"type":["string","null"],"pattern":"^-?\\d+\\.\\d{2}$","description":"Base rental price as a decimal string \"1234.50\" (ROUND_HALF_UP); null if not applicable."},"period":{"type":["string","null"],"enum":["hour","day","week","month",null],"description":"Period unit of the price: hour, day, week or month; null if the item has none configured."}},"required":["type","price","period"],"additionalProperties":false,"description":"Rental pricing configuration; null if not configured."},"insuranceEnabled":{"type":"boolean","description":"Whether the item allows insurance."},"discountEnabled":{"type":"boolean","description":"Whether the item allows discounts."},"bufferBefore":{"type":["number","null"],"description":"Buffer time reserved before the rental; null if not applicable."},"bufferBeforeUnit":{"type":["string","null"],"enum":["hour","day",null],"description":"Unit of the buffer before: hour or day; null if not applicable."},"bufferAfter":{"type":["number","null"],"description":"Buffer time reserved after the rental; null if not applicable."},"bufferAfterUnit":{"type":["string","null"],"enum":["hour","day",null],"description":"Unit of the buffer after: hour or day; null if not applicable."},"physicalProperties":{"type":["object","null"],"properties":{"weight":{"type":["number","null"],"description":"Item weight in kilograms; null if not recorded."},"width":{"type":["number","null"],"description":"Item width in centimeters; null if not recorded."},"height":{"type":["number","null"],"description":"Item height in centimeters; null if not recorded."},"length":{"type":["number","null"],"description":"Item length in centimeters; null if not recorded."},"volume":{"type":["number","null"],"description":"Item volume in cubic meters (m³); null if not recorded."},"current":{"type":["number","null"],"description":"Current draw in amperes; null if not recorded."},"power":{"type":["number","null"],"description":"Power in watts; null if not recorded."}},"required":["weight","width","height","length","volume","current","power"],"additionalProperties":false,"description":"Physical properties (weight and dimensions); null if not recorded."},"variants":{"type":"array","items":{"type":"object","properties":{"variantId":{"type":"string","description":"Unique identifier of the variant."},"variantName":{"type":"string","description":"Variant name."},"variantPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Rental price of the variant as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"salePrice":{"type":["string","null"],"pattern":"^-?\\d+\\.\\d{2}$","description":"Sale price of the variant as a decimal string \"1234.50\" (ROUND_HALF_UP); null if it has none."},"ean":{"type":["string","null"],"description":"EAN/barcode of the variant; null if not recorded."}},"required":["variantId","variantName","variantPrice","salePrice","ean"],"additionalProperties":false},"description":"Item variants (empty if the item is of type fixed)."},"tags":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the tag."},"name":{"type":"string","description":"Tag name."}},"required":["id","name"],"additionalProperties":false},"description":"Tags associated with the item."},"customFields":{"type":"object","additionalProperties":{},"description":"Custom field values by custom field identifier; the definitions are in /api/v1/custom-fields."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 with offset."},"updatedAt":{"type":"string","format":"date-time","description":"Last update date in ISO 8601 with offset."}},"required":["id","name","sku","description","orderInfo","ean","itemType","stockCalculationMethod","collectionId","collectionName","images","salePrice","depositValue","minStock","serializedItemsCount","pricingSettings","insuranceEnabled","discountEnabled","bufferBefore","bufferBeforeUnit","bufferAfter","bufferAfterUnit","physicalProperties","variants","tags","customFields","createdAt","updatedAt"],"additionalProperties":false,"description":"The item, as returned by the API."},"ItemList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ItemDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of item records in `data`, with its `pagination`."},"ItemDetailDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the item."},"name":{"type":"string","description":"Item name."},"sku":{"type":["string","null"],"description":"SKU reference of the item; null if not recorded."},"description":{"type":["string","null"],"description":"Item description; null if not recorded."},"orderInfo":{"type":["string","null"],"description":"Additional information for the order (preparation/delivery notes); null if not recorded."},"ean":{"type":["string","null"],"description":"EAN/barcode; null if not recorded."},"itemType":{"type":"string","enum":["fixed","variant"],"description":"Item type: fixed (simple item) or variant (item with variants)."},"stockCalculationMethod":{"type":"string","enum":["bulk","serialized"],"description":"Stock calculation method: bulk (in bulk, by quantity) or serialized (by serialized items)."},"collectionId":{"type":["string","null"],"description":"Identifier of the collection it belongs to; null if it is in none."},"collectionName":{"type":["string","null"],"description":"Name of the collection it belongs to; null if it is in none."},"images":{"type":"array","items":{"type":"string"},"description":"URLs of the item images."},"salePrice":{"type":["string","null"],"pattern":"^-?\\d+\\.\\d{2}$","description":"Sale price as a decimal string \"1234.50\" (ROUND_HALF_UP); null if it has none."},"depositValue":{"type":["string","null"],"pattern":"^-?\\d+\\.\\d{2}$","description":"Deposit amount as a decimal string \"1234.50\" (ROUND_HALF_UP); null if it has none."},"minStock":{"type":["number","null"],"description":"Minimum stock configured for alerts; null if not configured."},"serializedItemsCount":{"type":"number","description":"Number of serialized items registered for the item."},"pricingSettings":{"type":["object","null"],"properties":{"type":{"type":["string","null"],"enum":["periodPrice","fixedPrice","pricingStructure",null],"description":"Pricing mode: periodPrice (price per period), fixedPrice (fixed price) or pricingStructure (pricing structure); null if the item has none configured."},"price":{"type":["string","null"],"pattern":"^-?\\d+\\.\\d{2}$","description":"Base rental price as a decimal string \"1234.50\" (ROUND_HALF_UP); null if not applicable."},"period":{"type":["string","null"],"enum":["hour","day","week","month",null],"description":"Period unit of the price: hour, day, week or month; null if the item has none configured."}},"required":["type","price","period"],"additionalProperties":false,"description":"Rental pricing configuration; null if not configured."},"insuranceEnabled":{"type":"boolean","description":"Whether the item allows insurance."},"discountEnabled":{"type":"boolean","description":"Whether the item allows discounts."},"bufferBefore":{"type":["number","null"],"description":"Buffer time reserved before the rental; null if not applicable."},"bufferBeforeUnit":{"type":["string","null"],"enum":["hour","day",null],"description":"Unit of the buffer before: hour or day; null if not applicable."},"bufferAfter":{"type":["number","null"],"description":"Buffer time reserved after the rental; null if not applicable."},"bufferAfterUnit":{"type":["string","null"],"enum":["hour","day",null],"description":"Unit of the buffer after: hour or day; null if not applicable."},"physicalProperties":{"type":["object","null"],"properties":{"weight":{"type":["number","null"],"description":"Item weight in kilograms; null if not recorded."},"width":{"type":["number","null"],"description":"Item width in centimeters; null if not recorded."},"height":{"type":["number","null"],"description":"Item height in centimeters; null if not recorded."},"length":{"type":["number","null"],"description":"Item length in centimeters; null if not recorded."},"volume":{"type":["number","null"],"description":"Item volume in cubic meters (m³); null if not recorded."},"current":{"type":["number","null"],"description":"Current draw in amperes; null if not recorded."},"power":{"type":["number","null"],"description":"Power in watts; null if not recorded."}},"required":["weight","width","height","length","volume","current","power"],"additionalProperties":false,"description":"Physical properties (weight and dimensions); null if not recorded."},"variants":{"type":"array","items":{"type":"object","properties":{"variantId":{"type":"string","description":"Unique identifier of the variant."},"variantName":{"type":"string","description":"Variant name."},"variantPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Rental price of the variant as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"salePrice":{"type":["string","null"],"pattern":"^-?\\d+\\.\\d{2}$","description":"Sale price of the variant as a decimal string \"1234.50\" (ROUND_HALF_UP); null if it has none."},"ean":{"type":["string","null"],"description":"EAN/barcode of the variant; null if not recorded."}},"required":["variantId","variantName","variantPrice","salePrice","ean"],"additionalProperties":false},"description":"Item variants (empty if the item is of type fixed)."},"tags":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the tag."},"name":{"type":"string","description":"Tag name."}},"required":["id","name"],"additionalProperties":false},"description":"Tags associated with the item."},"customFields":{"type":"object","additionalProperties":{},"description":"Custom field values by custom field identifier; the definitions are in /api/v1/custom-fields."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 with offset."},"updatedAt":{"type":"string","format":"date-time","description":"Last update date in ISO 8601 with offset."},"replacementValue":{"type":["string","null"],"pattern":"^-?\\d+\\.\\d{2}$","description":"Replacement value of the item as a decimal string \"1234.50\" (ROUND_HALF_UP); null if not recorded."},"accessoryIds":{"type":"array","items":{"type":"string"},"description":"Identifiers of the items configured as accessories of this one."},"alternativeIds":{"type":"array","items":{"type":"string"},"description":"Identifiers of the items configured as alternatives of this one."}},"required":["id","name","sku","description","orderInfo","ean","itemType","stockCalculationMethod","collectionId","collectionName","images","salePrice","depositValue","minStock","serializedItemsCount","pricingSettings","insuranceEnabled","discountEnabled","bufferBefore","bufferBeforeUnit","bufferAfter","bufferAfterUnit","physicalProperties","variants","tags","customFields","createdAt","updatedAt","replacementValue","accessoryIds","alternativeIds"],"additionalProperties":false,"description":"The item in full, as returned by the API."},"ItemDetailResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ItemDetailDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the item detail in `data`."},"ItemCreateBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Item name. Required."},"sku":{"type":"string","description":"SKU reference. If omitted, the server generates the next available one for the account. Unique within the account."},"inventoryMethod":{"type":"string","enum":["bulk","serialized"],"default":"bulk","description":"How stock is tracked. bulk: total quantity per warehouse. serialized: each physical unit with its serial number. Cannot be changed once there is stock."},"collectionId":{"type":"string","description":"Identifier of the collection it is organized in; omit to leave it unclassified."},"tags":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"maxItems":50,"description":"Tags, by identifier or by name. A name that does not exist creates the tag."},"variationsEnabled":{"type":"boolean","description":"true creates an item with variants and its default variant. Omit or false for a simple item."},"showInOrderSearch":{"type":"boolean","description":"Whether the item appears in the item search within an order. Defaults to true."},"useSkuAsOrganizationMasterId":{"type":"boolean","description":"Only for organization accounts: copies the final SKU into organizationMasterId so the item can be matched across accounts. Defaults to false."}},"required":["name"],"additionalProperties":false,"description":"Body of the request that creates this item."},"ItemUpdateBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Item name."},"description":{"type":["string","null"],"description":"Item description; null clears it."},"sku":{"type":["string","null"],"minLength":1,"description":"SKU reference. Unique within the account; null clears it."},"collectionId":{"type":["string","null"],"minLength":1,"description":"Collection it belongs to; null removes it from any collection."},"orderInfo":{"type":["string","null"],"description":"Order information: preparation or delivery notes that do reach the customer; null clears it."},"synonyms":{"type":"array","items":{"type":"string"},"description":"Synonyms by which the item should be found in the search. Replaces the entire list."},"tags":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"maxItems":50,"description":"Tags, by identifier or by name; a name that does not exist creates the tag. Replaces the entire list."}},"additionalProperties":false,"description":"Body of the request that updates this item."},"ItemPhysicalPropertiesBody":{"type":"object","properties":{"weight":{"type":["number","null"],"minimum":0,"description":"Weight in kilograms; null clears it."},"length":{"type":["number","null"],"minimum":0,"description":"Length in centimeters; null clears it."},"width":{"type":["number","null"],"minimum":0,"description":"Width in centimeters; null clears it."},"height":{"type":["number","null"],"minimum":0,"description":"Height in centimeters; null clears it."},"volume":{"type":["number","null"],"minimum":0,"description":"Volume in cubic meters (m³); null clears it."},"current":{"type":["number","null"],"minimum":0,"description":"Current draw in amperes; null clears it."},"power":{"type":["number","null"],"minimum":0,"description":"Power in watts; null clears it."}},"additionalProperties":false,"description":"Body of the request that updates the physical properties of an item: weight, dimensions, volume and electrical data. Only the fields sent change."},"ItemPricingBody":{"type":"object","properties":{"pricingSettings":{"type":["object","null"],"properties":{"type":{"type":"string","enum":["periodPrice","fixedPrice","pricingStructure"],"description":"Pricing mode."},"price":{"type":"string","pattern":"^\\d{1,13}(\\.\\d{1,2})?$","description":"Base rental price, as a decimal string."},"period":{"type":"string","enum":["hour","day","week","month"],"description":"Period unit of the price."}},"required":["type","price","period"],"additionalProperties":false,"description":"Rental pricing, the three fields together; null clears it."},"salePrice":{"type":["string","null"],"pattern":"^\\d{1,13}(\\.\\d{1,2})?$","description":"Sale price, as a decimal string; null clears it."},"depositValue":{"type":["string","null"],"pattern":"^\\d{1,13}(\\.\\d{1,2})?$","description":"Deposit amount, as a decimal string; null clears it."},"replacementValue":{"type":["string","null"],"pattern":"^\\d{1,13}(\\.\\d{1,2})?$","description":"Replacement value, as a decimal string; null clears it."},"insuranceEnabled":{"type":"boolean","description":"Whether the item allows insurance."},"discountEnabled":{"type":"boolean","description":"Whether the item allows discounts."},"ean":{"type":["string","null"],"minLength":1,"description":"EAN or barcode; null clears it."},"bufferBefore":{"type":["number","null"],"minimum":0,"description":"Buffer time reserved BEFORE the rental; null clears it together with its unit."},"bufferBeforeUnit":{"type":["string","null"],"enum":["hour","day",null],"description":"Unit of the buffer before; null only together with `bufferBefore: null`."},"bufferAfter":{"type":["number","null"],"minimum":0,"description":"Buffer time reserved AFTER the rental; null clears it together with its unit."},"bufferAfterUnit":{"type":["string","null"],"enum":["hour","day",null],"description":"Unit of the buffer after; null only together with `bufferAfter: null`."}},"additionalProperties":false,"description":"Body of the request that updates the pricing of an item: price settings, sale price, deposit, replacement value, insurance, discount, barcode and buffers. Only the fields sent change."},"AvailabilityCommitment":{"type":"object","properties":{"orderId":{"type":"string","description":"Order that holds units of the item within the window."},"orderNumber":{"type":["string","null"],"description":"Number of that order; null if it has none yet."},"quantity":{"type":"number","description":"Peak units the order holds at the same time within the window."},"startDate":{"type":"string","format":"date-time","description":"Start of the period of its lines, in ISO 8601 UTC (not clipped to the window)."},"endDate":{"type":"string","format":"date-time","description":"End of the period of its lines, in ISO 8601 UTC (not clipped to the window)."}},"required":["orderId","orderNumber","quantity","startDate","endDate"],"additionalProperties":false,"description":"Order that consumes stock of the item within the queried window."},"AvailabilityResult":{"type":"object","properties":{"itemId":{"type":"string","description":"Identifier of the checked item."},"variantId":{"type":["string","null"],"description":"Identifier of the checked variant; null if the base item was checked."},"itemName":{"type":"string","description":"Name of the checked item."},"quantity":{"type":"integer","description":"Units requested for this item (1 if the request did not say)."},"available":{"type":"boolean","description":"true if `minRemaining` covers `quantity` at every point of the queried window."},"status":{"type":"string","enum":["ok","partial","none"],"description":"ok (the requested quantity is available), partial (some units are available, fewer than requested) or none (no units available)."},"totalStock":{"type":"number","description":"Total stock of the item."},"reserved":{"type":"number","description":"Reserved units overlapping the queried window."},"minRemaining":{"type":"number","description":"Minimum available at any point in the queried window."},"shortfall":{"type":"integer","description":"Units missing to serve `quantity` (0 when available)."},"temporaryAvailable":{"type":["number","null"],"description":"Additional temporary availability (e.g. borrowed/temporary stock); null if not applicable."},"conflictingPeriods":{"type":"array","items":{"type":"string"},"description":"Business days (YYYY-MM-DD, in the account timezone) within the window on which the stock does not cover `quantity`. Empty when available."},"commitments":{"type":"array","items":{"$ref":"#/components/schemas/AvailabilityCommitment"},"description":"Orders that consume stock of the item within the window (the lines behind `reserved`), earliest first. Empty when nothing is booked."},"checkedAt":{"type":"string","format":"date-time","description":"Moment the check was performed, in ISO 8601 with offset."}},"required":["itemId","variantId","itemName","quantity","available","status","totalStock","reserved","minRemaining","shortfall","temporaryAvailable","conflictingPeriods","commitments","checkedAt"],"additionalProperties":false,"description":"Availability of one requested item over the queried window."},"AvailabilityItemError":{"type":"object","properties":{"code":{"type":"string","enum":["not_found"],"description":"The item does not exist in the account."},"message":{"type":"string","description":"Human-readable explanation."}},"required":["code","message"],"additionalProperties":false,"description":"Why the item has no result."},"AvailabilityItemErrorEntry":{"type":"object","properties":{"itemId":{"type":"string","description":"Identifier the request asked for."},"variantId":{"type":["string","null"],"description":"Variant the request asked for; null if none."},"error":{"$ref":"#/components/schemas/AvailabilityItemError"}},"required":["itemId","variantId","error"],"additionalProperties":false,"description":"The requested item does not exist in the account: the entry carries an error instead of a result."},"AvailabilityCheckEntryDto":{"anyOf":[{"$ref":"#/components/schemas/AvailabilityResult"},{"$ref":"#/components/schemas/AvailabilityItemErrorEntry"}],"description":"Availability of one requested item, or a per-item error when the item does not exist."},"AvailabilityCheckEntryItems":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AvailabilityCheckEntryDto"}},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the availability check entry records in `data`."},"AvailabilityCheckBody":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"itemId":{"type":"string","minLength":1,"maxLength":100,"description":"Identifier of the item to check. Required."},"variantId":{"type":"string","minLength":1,"maxLength":100,"description":"Identifier of the specific variant to check; omit for the base item."},"transactionType":{"type":"string","enum":["rental","sale"],"description":"Type of transaction to check: rental or sale. Defaults to rental."},"quantity":{"type":"integer","minimum":1,"maximum":100000,"description":"Units you intend to book. Drives `available`, `shortfall`, `status` and `conflictingPeriods`. Defaults to 1."}},"required":["itemId"],"additionalProperties":false},"minItems":1,"maxItems":100,"description":"Batch of items to check (between 1 and 100)."},"startDate":{"type":"string","format":"date-time","description":"Start of the range to check (ISO 8601 with offset), shared by the whole batch."},"endDate":{"type":"string","format":"date-time","description":"End of the range to check (ISO 8601 with offset), shared by the whole batch; must be later than startDate."}},"required":["items","startDate","endDate"],"additionalProperties":false,"description":"Body of the request that checks the availability of one or more items for a date range."},"OrderDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique order identifier."},"orderNumber":{"type":"string","description":"Human-readable order number."},"externalReference":{"type":["string","null"],"description":"External reference of the order (for example, from the customer system); null if not recorded."},"status":{"type":"string","enum":["draft","reserved","prepared_partially","prepared","picked_up_partially","picked_up","returned_partially","returned","checked_in_partially","checked_in","archived","cancelled"],"description":"Raw order status as stored in the database (12 values): draft, reserved, prepared_partially, prepared, picked_up_partially, picked_up, returned_partially, returned, checked_in_partially, checked_in, archived or cancelled. `archived` is part of the stored set but an archived order is not visible to the API, so you will not observe it."},"startDate":{"type":"string","format":"date-time","description":"Start of the rental period in ISO 8601 with offset."},"endDate":{"type":"string","format":"date-time","description":"End of the rental period in ISO 8601 with offset."},"rentalDays":{"type":["number","null"],"description":"Number of billable rental days; null if not calculated."},"projectId":{"type":["string","null"],"description":"Identifier of the project the order belongs to; null if not linked."},"projectName":{"type":["string","null"],"description":"Name of the project the order belongs to; null if not linked."},"contact":{"type":["object","null"],"properties":{"id":{"type":"string","description":"Unique contact identifier."},"name":{"type":"string","description":"Contact name."}},"required":["id","name"],"additionalProperties":false,"description":"Compact reference to the order contact; null if none."},"itemsCount":{"type":"integer","description":"Number of items in the order."},"subTotalPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Subtotal before discounts and taxes, as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"discountTotal":{"type":["string","null"],"pattern":"^-?\\d+\\.\\d{2}$","description":"Total discounts as a decimal string \"1234.50\" (ROUND_HALF_UP); null if there is no discount."},"insuranceTotal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Insurance total as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"depositTotal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Deposit total as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"taxesPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Tax total as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"netPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Taxable base (net before taxes) as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"grossPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Total including taxes, as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"tags":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the tag."},"name":{"type":"string","description":"Tag name."}},"required":["id","name"],"additionalProperties":false},"description":"Tags attached to the order, with their identifier and name."},"customFields":{"type":"object","additionalProperties":{},"description":"Custom field values by custom field identifier; the definitions are in /api/v1/custom-fields."},"source":{"type":["string","null"],"description":"Source the order was created from (for example web, mobile, admin); null if not recorded."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 with offset."},"updatedAt":{"type":"string","format":"date-time","description":"Last update date in ISO 8601 with offset."}},"required":["id","orderNumber","externalReference","status","startDate","endDate","rentalDays","projectId","projectName","contact","itemsCount","subTotalPrice","discountTotal","insuranceTotal","depositTotal","taxesPrice","netPrice","grossPrice","tags","customFields","source","createdAt","updatedAt"],"additionalProperties":false,"description":"The order, as returned by the API."},"OrderList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OrderDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of order records in `data`, with its `pagination`."},"OrderDetailDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique order identifier."},"orderNumber":{"type":"string","description":"Human-readable order number."},"externalReference":{"type":["string","null"],"description":"External reference of the order (for example, from the customer system); null if not recorded."},"status":{"type":"string","enum":["draft","reserved","prepared_partially","prepared","picked_up_partially","picked_up","returned_partially","returned","checked_in_partially","checked_in","archived","cancelled"],"description":"Raw order status as stored in the database (12 values): draft, reserved, prepared_partially, prepared, picked_up_partially, picked_up, returned_partially, returned, checked_in_partially, checked_in, archived or cancelled. `archived` is part of the stored set but an archived order is not visible to the API, so you will not observe it."},"startDate":{"type":"string","format":"date-time","description":"Start of the rental period in ISO 8601 with offset."},"endDate":{"type":"string","format":"date-time","description":"End of the rental period in ISO 8601 with offset."},"rentalDays":{"type":["number","null"],"description":"Number of billable rental days; null if not calculated."},"projectId":{"type":["string","null"],"description":"Identifier of the project the order belongs to; null if not linked."},"projectName":{"type":["string","null"],"description":"Name of the project the order belongs to; null if not linked."},"contact":{"type":["object","null"],"properties":{"id":{"type":"string","description":"Unique contact identifier."},"name":{"type":"string","description":"Contact name."}},"required":["id","name"],"additionalProperties":false,"description":"Compact reference to the order contact; null if none."},"itemsCount":{"type":"integer","description":"Number of items in the order."},"subTotalPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Subtotal before discounts and taxes, as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"discountTotal":{"type":["string","null"],"pattern":"^-?\\d+\\.\\d{2}$","description":"Total discounts as a decimal string \"1234.50\" (ROUND_HALF_UP); null if there is no discount."},"insuranceTotal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Insurance total as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"depositTotal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Deposit total as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"taxesPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Tax total as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"netPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Taxable base (net before taxes) as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"grossPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Total including taxes, as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"tags":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the tag."},"name":{"type":"string","description":"Tag name."}},"required":["id","name"],"additionalProperties":false},"description":"Tags attached to the order, with their identifier and name."},"customFields":{"type":"object","additionalProperties":{},"description":"Custom field values by custom field identifier; the definitions are in /api/v1/custom-fields."},"source":{"type":["string","null"],"description":"Source the order was created from (for example web, mobile, admin); null if not recorded."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 with offset."},"updatedAt":{"type":"string","format":"date-time","description":"Last update date in ISO 8601 with offset."},"billingAddress":{"type":["object","null"],"properties":{"label":{"type":["string","null"],"description":"Descriptive label of the address; null if not recorded."},"addressLine1":{"type":["string","null"],"description":"First address line; null if not recorded."},"addressLine2":{"type":["string","null"],"description":"Second address line; null if not recorded."},"city":{"type":["string","null"],"description":"City; null if not recorded."},"province":{"type":["string","null"],"description":"Province or region; null if not recorded."},"postcode":{"type":["string","null"],"description":"Postal code; null if not recorded."},"country":{"type":["string","null"],"description":"Country; null if not recorded."}},"required":["label","addressLine1","addressLine2","city","province","postcode","country"],"additionalProperties":false,"description":"Billing address of the order; null if none."},"shippingAddress":{"type":["object","null"],"properties":{"label":{"type":["string","null"],"description":"Descriptive label of the address; null if not recorded."},"addressLine1":{"type":["string","null"],"description":"First address line; null if not recorded."},"addressLine2":{"type":["string","null"],"description":"Second address line; null if not recorded."},"city":{"type":["string","null"],"description":"City; null if not recorded."},"province":{"type":["string","null"],"description":"Province or region; null if not recorded."},"postcode":{"type":["string","null"],"description":"Postal code; null if not recorded."},"country":{"type":["string","null"],"description":"Country; null if not recorded."}},"required":["label","addressLine1","addressLine2","city","province","postcode","country"],"additionalProperties":false,"description":"Shipping address of the order; null if none."},"contactPerson":{"type":["object","null"],"properties":{"id":{"type":"string","description":"Unique contact identifier."},"name":{"type":"string","description":"Contact name."}},"required":["id","name"],"additionalProperties":false,"description":"Contact person linked to the order; null if none."},"quotes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the referenced document."},"number":{"type":["string","null"],"description":"Document number; null until it is numbered."},"status":{"type":["string","null"],"description":"Document status at the time the reference was written; null if not recorded. Informational: it may be out of date."}},"required":["id","number","status"],"additionalProperties":false},"description":"Informational references to quotes generated from the order."},"invoices":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the referenced document."},"number":{"type":["string","null"],"description":"Document number; null until it is numbered."},"status":{"type":["string","null"],"description":"Document status at the time the reference was written; null if not recorded. Informational: it may be out of date."}},"required":["id","number","status"],"additionalProperties":false},"description":"Informational references to invoices generated from the order."},"proformas":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the referenced document."},"number":{"type":["string","null"],"description":"Document number; null until it is numbered."},"status":{"type":["string","null"],"description":"Document status at the time the reference was written; null if not recorded. Informational: it may be out of date."}},"required":["id","number","status"],"additionalProperties":false},"description":"Informational references to proformas generated from the order."}},"required":["id","orderNumber","externalReference","status","startDate","endDate","rentalDays","projectId","projectName","contact","itemsCount","subTotalPrice","discountTotal","insuranceTotal","depositTotal","taxesPrice","netPrice","grossPrice","tags","customFields","source","createdAt","updatedAt","billingAddress","shippingAddress","contactPerson","quotes","invoices","proformas"],"additionalProperties":false,"description":"The order in full, as returned by the API."},"OrderDetailResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrderDetailDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the order detail in `data`."},"OrderCreateBody":{"type":"object","properties":{"contactId":{"type":"string","minLength":1,"maxLength":100,"description":"Identifier of the order customer. It must belong to the account of the API key."},"projectId":{"type":"string","minLength":1,"maxLength":100,"description":"Project the order is assigned to; omitted for a standalone order."},"startDate":{"type":"string","format":"date-time","description":"Rental start (ISO 8601 with offset)."},"endDate":{"type":"string","format":"date-time","description":"Rental end (ISO 8601 with offset); it must be later than startDate."},"lines":{"type":"array","items":{"type":"object","properties":{"itemId":{"type":"string","minLength":1,"maxLength":100,"description":"Catalog item identifier. It must belong to the account of the API key."},"quantity":{"type":"integer","minimum":1,"maximum":9999,"description":"Requested units of the item."},"variantId":{"type":"string","minLength":1,"maxLength":100,"description":"Identifier of the specific variant; omitted for the base item."}},"required":["itemId","quantity"],"additionalProperties":false},"minItems":1,"maxItems":100,"description":"Requested material (between 1 and 100 lines)."}},"required":["contactId","startDate","endDate","lines"],"additionalProperties":false,"description":"Body of the request that creates this order."},"OrderLineDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique line identifier."},"orderId":{"type":"string","description":"Identifier of the order the line belongs to."},"resourceType":{"type":"string","enum":["item","kit","space","vehicle","personnel","service","custom","section","type_group"],"description":"Resource type of the line. Lines of type section and type_group are presentation groupings with no associated resource."},"transactionType":{"type":"string","enum":["rental","sale"],"description":"Nature of the line: rental or sale."},"status":{"type":"string","enum":["draft","reserved","prepared","picked_up","sold","returned","checked_in","cancelled","lost"],"description":"Status of the line within the order flow."},"position":{"type":"integer","description":"Display position of the line within the order, starting at 0."},"addedDuringDelivery":{"type":"boolean","description":"true if the line was added during the delivery process rather than in the original order."},"itemId":{"type":["string","null"],"description":"Catalog item identifier; null if the line is not of type item."},"itemName":{"type":["string","null"],"description":"Name of the item, space, service or custom element of the line."},"variantId":{"type":["string","null"],"description":"Identifier of the item variant; null if not applicable."},"spaceId":{"type":["string","null"],"description":"Space identifier; null if the line is not of type space."},"quantity":{"type":"number","description":"Units of the line."},"serials":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the serialized item."},"code":{"type":["string","null"],"description":"Internal code of the unit; null if none."},"serialNumber":{"type":["string","null"],"description":"Manufacturer serial number; null if not recorded."}},"required":["id","code","serialNumber"],"description":"Specific physical unit assigned to the line."},"description":"Specific physical units assigned. Empty for non-serialized items or when not yet assigned."},"startDate":{"type":["string","null"],"format":"date-time","description":"Start of the line period in ISO 8601 UTC; null if it inherits the order period."},"endDate":{"type":["string","null"],"format":"date-time","description":"End of the line period in ISO 8601 UTC; null if it inherits the order period."},"rentalDays":{"type":["number","null"],"description":"Billable rental days of the line; null if not calculated."},"unitPrice":{"type":["string","null"],"pattern":"^-?\\d+\\.\\d{2}$","description":"Net unit price as a decimal string \"1234.50\"; null if the line has no price of its own."},"linePrice":{"type":["string","null"],"pattern":"^-?\\d+\\.\\d{2}$","description":"Total net amount of the line as a decimal string \"1234.50\"; null if not calculated."},"free":{"type":"boolean","description":"true if the line is explicitly billed at zero."},"notes":{"type":["string","null"],"description":"Line notes; null if none."}},"required":["id","orderId","resourceType","transactionType","status","position","addedDuringDelivery","itemId","itemName","variantId","spaceId","quantity","serials","startDate","endDate","rentalDays","unitPrice","linePrice","free","notes"],"description":"Order line: which resource it carries, how much, when and at what sale price."},"OrderLineList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OrderLineDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of order line records in `data`, with its `pagination`."},"InvoiceDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique invoice identifier."},"invoiceNumber":{"type":["string","null"],"description":"Invoice number; null while it is a draft (the number is assigned on validation)."},"status":{"type":"string","enum":["draft","validated","voided"],"description":"Document lifecycle status: draft, validated (validated and numbered) or voided."},"isRectification":{"type":"boolean","description":"Whether the invoice rectifies a previous one. Invoices created in Filmo are never rectifications, and credit notes are served by `/api/v1/credit-notes`; but `/api/v1/invoices` can still return imported rectifying documents (for example from a Rentman import) with this set to true, so deduplicate them against the credit notes by number."},"invoiceDate":{"type":["string","null"],"format":"date-time","description":"Issue date in ISO 8601 with offset; null while it is a draft."},"dueDate":{"type":["string","null"],"format":"date-time","description":"Due date in ISO 8601 with offset; null if not set."},"currency":{"type":"string","description":"Invoice currency as an ISO 4217 code (for example \"EUR\")."},"contact":{"type":["object","null"],"properties":{"id":{"type":"string","description":"Unique contact identifier."},"name":{"type":"string","description":"Contact name."}},"required":["id","name"],"additionalProperties":false,"description":"Compact reference to the invoiced contact; null if none."},"orderId":{"type":["string","null"],"description":"Identifier of the source order; null if the invoice does not come from an order."},"orderNumber":{"type":["string","null"],"description":"Number of the source order; null if the invoice does not come from an order."},"projectId":{"type":["string","null"],"description":"Identifier of the linked project; null if not linked."},"subTotal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Subtotal before discounts and taxes, as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"discountTotal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Total discounts as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"taxesPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Tax total as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"netPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Taxable base (net before taxes) as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"grossPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Total including taxes, as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"totalPaid":{"type":["string","null"],"pattern":"^-?\\d+\\.\\d{2}$","description":"Amount collected to date as a decimal string \"1234.50\" (ROUND_HALF_UP); null if not recorded."},"paymentStatus":{"type":"string","enum":["unpaid","partially_paid","paid","overpaid","overdue","voided"],"description":"Payment status: unpaid (nothing collected yet, also for invoices without a recorded collection), partially_paid, paid, overpaid (collected above the total), overdue (past due and unpaid) or voided (the document is voided, whatever was collected before). The `paymentStatus` filter uses the same values."},"paymentMethod":{"type":["string","null"],"description":"Payment method of the invoice; null if not recorded."},"tags":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the tag."},"name":{"type":"string","description":"Tag name."}},"required":["id","name"],"additionalProperties":false},"description":"Tags attached to the invoice, with their identifier and name."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 with offset."},"updatedAt":{"type":"string","format":"date-time","description":"Last update date in ISO 8601 with offset."}},"required":["id","invoiceNumber","status","isRectification","invoiceDate","dueDate","currency","contact","orderId","orderNumber","projectId","subTotal","discountTotal","taxesPrice","netPrice","grossPrice","totalPaid","paymentStatus","paymentMethod","tags","createdAt","updatedAt"],"additionalProperties":false,"description":"The invoice, as returned by the API."},"InvoiceList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/InvoiceDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of invoice records in `data`, with its `pagination`."},"InvoiceDetailDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique invoice identifier."},"invoiceNumber":{"type":["string","null"],"description":"Invoice number; null while it is a draft (the number is assigned on validation)."},"status":{"type":"string","enum":["draft","validated","voided"],"description":"Document lifecycle status: draft, validated (validated and numbered) or voided."},"isRectification":{"type":"boolean","description":"Whether the invoice rectifies a previous one. Invoices created in Filmo are never rectifications, and credit notes are served by `/api/v1/credit-notes`; but `/api/v1/invoices` can still return imported rectifying documents (for example from a Rentman import) with this set to true, so deduplicate them against the credit notes by number."},"invoiceDate":{"type":["string","null"],"format":"date-time","description":"Issue date in ISO 8601 with offset; null while it is a draft."},"dueDate":{"type":["string","null"],"format":"date-time","description":"Due date in ISO 8601 with offset; null if not set."},"currency":{"type":"string","description":"Invoice currency as an ISO 4217 code (for example \"EUR\")."},"contact":{"type":["object","null"],"properties":{"id":{"type":"string","description":"Unique contact identifier."},"name":{"type":"string","description":"Contact name."}},"required":["id","name"],"additionalProperties":false,"description":"Compact reference to the invoiced contact; null if none."},"orderId":{"type":["string","null"],"description":"Identifier of the source order; null if the invoice does not come from an order."},"orderNumber":{"type":["string","null"],"description":"Number of the source order; null if the invoice does not come from an order."},"projectId":{"type":["string","null"],"description":"Identifier of the linked project; null if not linked."},"subTotal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Subtotal before discounts and taxes, as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"discountTotal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Total discounts as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"taxesPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Tax total as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"netPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Taxable base (net before taxes) as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"grossPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Total including taxes, as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"totalPaid":{"type":["string","null"],"pattern":"^-?\\d+\\.\\d{2}$","description":"Amount collected to date as a decimal string \"1234.50\" (ROUND_HALF_UP); null if not recorded."},"paymentStatus":{"type":"string","enum":["unpaid","partially_paid","paid","overpaid","overdue","voided"],"description":"Payment status: unpaid (nothing collected yet, also for invoices without a recorded collection), partially_paid, paid, overpaid (collected above the total), overdue (past due and unpaid) or voided (the document is voided, whatever was collected before). The `paymentStatus` filter uses the same values."},"paymentMethod":{"type":["string","null"],"description":"Payment method of the invoice; null if not recorded."},"tags":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the tag."},"name":{"type":"string","description":"Tag name."}},"required":["id","name"],"additionalProperties":false},"description":"Tags attached to the invoice, with their identifier and name."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 with offset."},"updatedAt":{"type":"string","format":"date-time","description":"Last update date in ISO 8601 with offset."},"projectName":{"type":["string","null"],"description":"Name of the linked project; null if not linked."},"taxBreakdown":{"type":["array","null"],"items":{"type":"object","properties":{"taxType":{"type":"string","description":"Tax type key (for example \"IVA_21\")."},"label":{"type":"string","description":"Human-readable tax label."},"rate":{"type":"number","description":"Tax rate applied, as a percentage (for example 21 for 21%)."},"baseAmount":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Taxable base the tax is applied to, as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"amount":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Tax amount as a decimal string \"1234.50\" (ROUND_HALF_UP)."}},"required":["taxType","label","rate","baseAmount","amount"],"additionalProperties":false},"description":"Tax breakdown by type; null if not calculated."},"productDiscountTotal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Total discounts applied at product level, as a decimal string \"1234.50\" (ROUND_HALF_UP). productDiscountTotal + globalDiscountTotal = discountTotal."},"globalDiscountTotal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Global discount total of the document, as a decimal string \"1234.50\" (ROUND_HALF_UP). productDiscountTotal + globalDiscountTotal = discountTotal."},"insuranceTotal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Insurance total as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"depositTotal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Deposit total as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"exchangeRate":{"type":["number","null"],"description":"Exchange rate applied when the currency differs from the base currency; null if not applicable."},"billingAddress":{"type":["object","null"],"properties":{"label":{"type":["string","null"],"description":"Descriptive label of the address; null if not recorded."},"addressLine1":{"type":["string","null"],"description":"First address line; null if not recorded."},"addressLine2":{"type":["string","null"],"description":"Second address line; null if not recorded."},"city":{"type":["string","null"],"description":"City; null if not recorded."},"province":{"type":["string","null"],"description":"Province or region; null if not recorded."},"postcode":{"type":["string","null"],"description":"Postal code; null if not recorded."},"country":{"type":["string","null"],"description":"Country; null if not recorded."}},"required":["label","addressLine1","addressLine2","city","province","postcode","country"],"additionalProperties":false,"description":"Billing address; null if not recorded."},"sourceQuoteIds":{"type":["array","null"],"items":{"type":"string"},"description":"Identifiers of the source quotes; null if the invoice does not come from quotes."},"sourceProformaIds":{"type":["array","null"],"items":{"type":"string"},"description":"Identifiers of the source proformas; null if the invoice does not come from proformas."}},"required":["id","invoiceNumber","status","isRectification","invoiceDate","dueDate","currency","contact","orderId","orderNumber","projectId","subTotal","discountTotal","taxesPrice","netPrice","grossPrice","totalPaid","paymentStatus","paymentMethod","tags","createdAt","updatedAt","projectName","taxBreakdown","productDiscountTotal","globalDiscountTotal","insuranceTotal","depositTotal","exchangeRate","billingAddress","sourceQuoteIds","sourceProformaIds"],"additionalProperties":false,"description":"The invoice in full, as returned by the API."},"InvoiceDetailResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/InvoiceDetailDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the invoice detail in `data`."},"QuoteDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique quote identifier (container)."},"quoteNumber":{"type":"string","description":"Human-readable quote number."},"versionNumber":{"type":"integer","description":"Number of the active version of the quote."},"status":{"type":"string","enum":["draft","validated"],"description":"Document lifecycle status of the active version: draft or validated (validated and numbered)."},"operativeStatus":{"type":"string","enum":["pending","confirmed","cancelled","superseded"],"description":"Commercial status of the active version: pending (awaiting an answer), confirmed (accepted), cancelled (rejected/cancelled) or superseded (replaced)."},"issueDate":{"type":["string","null"],"format":"date-time","description":"Issue date of the active version in ISO 8601 with offset; null if not issued."},"validUntil":{"type":["string","null"],"format":"date-time","description":"Validity date of the quote in ISO 8601 with offset; null if not set."},"startDate":{"type":"string","format":"date-time","description":"Start of the quoted rental period in ISO 8601 with offset."},"endDate":{"type":"string","format":"date-time","description":"End of the quoted rental period in ISO 8601 with offset."},"currency":{"type":"string","description":"Quote currency as an ISO 4217 code (for example \"EUR\")."},"contact":{"type":["object","null"],"properties":{"id":{"type":"string","description":"Unique contact identifier."},"name":{"type":"string","description":"Contact name."}},"required":["id","name"],"additionalProperties":false,"description":"Compact reference to the quote contact; null if none."},"orderId":{"type":["string","null"],"description":"Identifier of the linked order; null if not linked."},"orderNumber":{"type":["string","null"],"description":"Number of the linked order; null if not linked."},"projectId":{"type":["string","null"],"description":"Identifier of the linked project; null if not linked."},"subTotal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Subtotal before discounts and taxes, as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"discountTotal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Total discounts as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"taxesPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Tax total as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"netPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Taxable base (net before taxes) as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"grossPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Total including taxes, as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"totalPaid":{"type":["string","null"],"pattern":"^-?\\d+\\.\\d{2}$","description":"Amount collected against the quote as a decimal string \"1234.50\" (ROUND_HALF_UP); null if not recorded."},"createdAt":{"type":"string","format":"date-time","description":"Creation date of the container in ISO 8601 with offset."},"updatedAt":{"type":"string","format":"date-time","description":"Last update date in ISO 8601 with offset."}},"required":["id","quoteNumber","versionNumber","status","operativeStatus","issueDate","validUntil","startDate","endDate","currency","contact","orderId","orderNumber","projectId","subTotal","discountTotal","taxesPrice","netPrice","grossPrice","totalPaid","createdAt","updatedAt"],"additionalProperties":false,"description":"The quote, as returned by the API."},"QuoteList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/QuoteDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of quote records in `data`, with its `pagination`."},"QuoteDetailDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique quote identifier (container)."},"quoteNumber":{"type":"string","description":"Human-readable quote number."},"versionNumber":{"type":"integer","description":"Number of the active version of the quote."},"status":{"type":"string","enum":["draft","validated"],"description":"Document lifecycle status of the active version: draft or validated (validated and numbered)."},"operativeStatus":{"type":"string","enum":["pending","confirmed","cancelled","superseded"],"description":"Commercial status of the active version: pending (awaiting an answer), confirmed (accepted), cancelled (rejected/cancelled) or superseded (replaced)."},"issueDate":{"type":["string","null"],"format":"date-time","description":"Issue date of the active version in ISO 8601 with offset; null if not issued."},"validUntil":{"type":["string","null"],"format":"date-time","description":"Validity date of the quote in ISO 8601 with offset; null if not set."},"startDate":{"type":"string","format":"date-time","description":"Start of the quoted rental period in ISO 8601 with offset."},"endDate":{"type":"string","format":"date-time","description":"End of the quoted rental period in ISO 8601 with offset."},"currency":{"type":"string","description":"Quote currency as an ISO 4217 code (for example \"EUR\")."},"contact":{"type":["object","null"],"properties":{"id":{"type":"string","description":"Unique contact identifier."},"name":{"type":"string","description":"Contact name."}},"required":["id","name"],"additionalProperties":false,"description":"Compact reference to the quote contact; null if none."},"orderId":{"type":["string","null"],"description":"Identifier of the linked order; null if not linked."},"orderNumber":{"type":["string","null"],"description":"Number of the linked order; null if not linked."},"projectId":{"type":["string","null"],"description":"Identifier of the linked project; null if not linked."},"subTotal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Subtotal before discounts and taxes, as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"discountTotal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Total discounts as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"taxesPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Tax total as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"netPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Taxable base (net before taxes) as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"grossPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Total including taxes, as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"totalPaid":{"type":["string","null"],"pattern":"^-?\\d+\\.\\d{2}$","description":"Amount collected against the quote as a decimal string \"1234.50\" (ROUND_HALF_UP); null if not recorded."},"createdAt":{"type":"string","format":"date-time","description":"Creation date of the container in ISO 8601 with offset."},"updatedAt":{"type":"string","format":"date-time","description":"Last update date in ISO 8601 with offset."},"projectName":{"type":["string","null"],"description":"Name of the linked project; null if not linked."},"taxBreakdown":{"type":["array","null"],"items":{"type":"object","properties":{"taxType":{"type":"string","description":"Tax type key (for example \"IVA_21\")."},"label":{"type":"string","description":"Human-readable tax label."},"rate":{"type":"number","description":"Tax rate applied, as a percentage (for example 21 for 21%)."},"baseAmount":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Taxable base the tax is applied to, as a decimal string \"1234.50\" (ROUND_HALF_UP)."},"amount":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Tax amount as a decimal string \"1234.50\" (ROUND_HALF_UP)."}},"required":["taxType","label","rate","baseAmount","amount"],"additionalProperties":false},"description":"Tax breakdown by type; null if not calculated."}},"required":["id","quoteNumber","versionNumber","status","operativeStatus","issueDate","validUntil","startDate","endDate","currency","contact","orderId","orderNumber","projectId","subTotal","discountTotal","taxesPrice","netPrice","grossPrice","totalPaid","createdAt","updatedAt","projectName","taxBreakdown"],"additionalProperties":false,"description":"The quote in full, as returned by the API."},"QuoteDetailResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/QuoteDetailDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the quote detail in `data`."},"ProjectDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique project identifier."},"projectNumber":{"type":["string","null"],"description":"Human-readable project number; null if not numbered."},"name":{"type":"string","description":"Project name."},"color":{"type":["string","null"],"description":"Color associated with the project (for the UI); null if none."},"externalReference":{"type":["string","null"],"description":"External reference of the project (for example, from the customer system); null if not recorded."},"projectTypeId":{"type":["string","null"],"description":"Project type identifier; null if the project has no type."},"projectType":{"type":["object","null"],"properties":{"id":{"type":"string","description":"Unique project type identifier."},"name":{"type":"string","description":"Project type name."},"color":{"type":["string","null"],"description":"Color associated with the project type (for the UI); null if none."}},"required":["id","name","color"],"additionalProperties":false,"description":"Compact reference to the project type; null if none."},"contact":{"type":["object","null"],"properties":{"id":{"type":"string","description":"Unique contact identifier."},"name":{"type":"string","description":"Contact name."}},"required":["id","name"],"additionalProperties":false,"description":"Compact reference to the project contact; null if none."},"location":{"type":"object","properties":{"name":{"type":["string","null"],"description":"Name of the place/location; null if not recorded."},"address":{"type":["string","null"],"description":"Address of the location; null if not recorded."},"city":{"type":["string","null"],"description":"City of the location; null if not recorded."},"postalCode":{"type":["string","null"],"description":"Postal code of the location; null if not recorded."},"province":{"type":["string","null"],"description":"Province or region of the location; null if not recorded."},"country":{"type":["string","null"],"description":"Country of the location; null if not recorded."},"lat":{"type":["number","null"],"description":"Latitude of the location; null if not recorded."},"lng":{"type":["number","null"],"description":"Longitude of the location; null if not recorded."}},"required":["name","address","city","postalCode","province","country","lat","lng"],"additionalProperties":false,"description":"Project location; its inner fields are null when not recorded."},"startDate":{"type":"string","format":"date-time","description":"Project start date in ISO 8601 with offset."},"endDate":{"type":"string","format":"date-time","description":"Project end date in ISO 8601 with offset."},"status":{"type":"string","enum":["draft","budgeted","confirmed","in_progress","invoiced","completed","cancelled","archived"],"description":"Project status: draft, budgeted, confirmed, in_progress, invoiced, completed, cancelled or archived. `archived` is a LEGACY status that appears in old data; the current archived state is expressed by the `archived` boolean of this same DTO."},"archived":{"type":"boolean","description":"Whether the project is archived."},"orderIds":{"type":"array","items":{"type":"string"},"description":"Identifiers of the project orders. Order details are obtained from GET /api/v1/orders?projectId=."},"totalOrders":{"type":"integer","description":"Total number of orders in the project (equals orderIds.length)."},"tags":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the tag."},"name":{"type":"string","description":"Tag name."}},"required":["id","name"],"additionalProperties":false},"description":"Tags attached to the project, with their identifier and name."},"customFields":{"type":"object","additionalProperties":{},"description":"Custom field values by custom field identifier; the definitions are in /api/v1/custom-fields."},"source":{"type":["string","null"],"description":"Source the project was created from; null if not recorded."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 with offset."},"updatedAt":{"type":"string","format":"date-time","description":"Last update date in ISO 8601 with offset."}},"required":["id","projectNumber","name","color","externalReference","projectTypeId","projectType","contact","location","startDate","endDate","status","archived","orderIds","totalOrders","tags","customFields","source","createdAt","updatedAt"],"additionalProperties":false,"description":"The project, as returned by the API."},"ProjectList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ProjectDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of project records in `data`, with its `pagination`."},"ProjectDetailDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique project identifier."},"projectNumber":{"type":["string","null"],"description":"Human-readable project number; null if not numbered."},"name":{"type":"string","description":"Project name."},"color":{"type":["string","null"],"description":"Color associated with the project (for the UI); null if none."},"externalReference":{"type":["string","null"],"description":"External reference of the project (for example, from the customer system); null if not recorded."},"projectTypeId":{"type":["string","null"],"description":"Project type identifier; null if the project has no type."},"projectType":{"type":["object","null"],"properties":{"id":{"type":"string","description":"Unique project type identifier."},"name":{"type":"string","description":"Project type name."},"color":{"type":["string","null"],"description":"Color associated with the project type (for the UI); null if none."}},"required":["id","name","color"],"additionalProperties":false,"description":"Compact reference to the project type; null if none."},"contact":{"type":["object","null"],"properties":{"id":{"type":"string","description":"Unique contact identifier."},"name":{"type":"string","description":"Contact name."}},"required":["id","name"],"additionalProperties":false,"description":"Compact reference to the project contact; null if none."},"location":{"type":"object","properties":{"name":{"type":["string","null"],"description":"Name of the place/location; null if not recorded."},"address":{"type":["string","null"],"description":"Address of the location; null if not recorded."},"city":{"type":["string","null"],"description":"City of the location; null if not recorded."},"postalCode":{"type":["string","null"],"description":"Postal code of the location; null if not recorded."},"province":{"type":["string","null"],"description":"Province or region of the location; null if not recorded."},"country":{"type":["string","null"],"description":"Country of the location; null if not recorded."},"lat":{"type":["number","null"],"description":"Latitude of the location; null if not recorded."},"lng":{"type":["number","null"],"description":"Longitude of the location; null if not recorded."}},"required":["name","address","city","postalCode","province","country","lat","lng"],"additionalProperties":false,"description":"Project location; its inner fields are null when not recorded."},"startDate":{"type":"string","format":"date-time","description":"Project start date in ISO 8601 with offset."},"endDate":{"type":"string","format":"date-time","description":"Project end date in ISO 8601 with offset."},"status":{"type":"string","enum":["draft","budgeted","confirmed","in_progress","invoiced","completed","cancelled","archived"],"description":"Project status: draft, budgeted, confirmed, in_progress, invoiced, completed, cancelled or archived. `archived` is a LEGACY status that appears in old data; the current archived state is expressed by the `archived` boolean of this same DTO."},"archived":{"type":"boolean","description":"Whether the project is archived."},"orderIds":{"type":"array","items":{"type":"string"},"description":"Identifiers of the project orders. Order details are obtained from GET /api/v1/orders?projectId=."},"totalOrders":{"type":"integer","description":"Total number of orders in the project (equals orderIds.length)."},"tags":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the tag."},"name":{"type":"string","description":"Tag name."}},"required":["id","name"],"additionalProperties":false},"description":"Tags attached to the project, with their identifier and name."},"customFields":{"type":"object","additionalProperties":{},"description":"Custom field values by custom field identifier; the definitions are in /api/v1/custom-fields."},"source":{"type":["string","null"],"description":"Source the project was created from; null if not recorded."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 with offset."},"updatedAt":{"type":"string","format":"date-time","description":"Last update date in ISO 8601 with offset."}},"required":["id","projectNumber","name","color","externalReference","projectTypeId","projectType","contact","location","startDate","endDate","status","archived","orderIds","totalOrders","tags","customFields","source","createdAt","updatedAt"],"additionalProperties":false,"description":"The project in full, as returned by the API."},"ProjectDetailResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ProjectDetailDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the project detail in `data`."},"ProjectCreateBody":{"type":"object","properties":{"name":{"type":"string","minLength":3,"maxLength":200,"description":"Project name. At least three characters, as the domain requires."},"startDate":{"type":"string","format":"date-time","description":"Project start (ISO 8601 with offset)."},"endDate":{"type":"string","format":"date-time","description":"Project end (ISO 8601 with offset). It cannot be earlier than startDate; the same instant is a one-day project."},"contactId":{"type":"string","minLength":1,"maxLength":100,"description":"Project customer. It must belong to the account of the API key."},"projectTypeId":{"type":"string","minLength":1,"maxLength":100,"description":"Project type. Resolve it against /api/v1/project-types; it must belong to the account of the API key."},"externalReference":{"type":"string","maxLength":200,"description":"Free-form reference to match the project with an external system."},"location":{"type":"object","properties":{"name":{"type":"string","maxLength":200,"description":"Name of the place, for example \"Main stage\"."},"address":{"type":"string","maxLength":500,"description":"Street address."},"city":{"type":"string","maxLength":200,"description":"City."},"postalCode":{"type":"string","maxLength":20,"description":"Postal code."},"province":{"type":"string","maxLength":200,"description":"Province or region."},"country":{"type":"string","maxLength":200,"description":"Country."},"lat":{"type":"number","minimum":-90,"maximum":90,"description":"Latitude in decimal degrees."},"lng":{"type":"number","minimum":-180,"maximum":180,"description":"Longitude in decimal degrees."}},"additionalProperties":false,"description":"Physical location of the project (a stage, a client site). Only the fields sent are recorded."}},"required":["name","startDate","endDate"],"additionalProperties":false,"description":"Body of the request that creates this project."},"ProjectArchiveBody":{"type":"object","properties":{"archived":{"type":"boolean","description":"true removes the project from the active views; false brings it back."}},"required":["archived"],"additionalProperties":false,"description":"Body of the request that archives or restores a project."},"PaymentDto":{"type":"object","properties":{"id":{"type":"string","description":"Payment identifier."},"direction":{"type":"string","description":"in when money comes in (a collection) and out when it goes out (a payment)."},"amount":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Payment amount as a decimal string, in the indicated currency."},"currency":{"type":"string","description":"Payment currency, as an ISO 4217 code."},"date":{"type":"string","format":"date-time","description":"Payment date in ISO 8601 UTC."},"type":{"type":"string","description":"normal, or deposit when it is an advance payment."},"treasuryAccountId":{"type":"string","description":"Treasury account the payment goes through."},"contactId":{"type":["string","null"],"description":"Customer or supplier of the payment; null if not declared."},"reference":{"type":["string","null"],"description":"External reference of the payment; null if it has none."},"linkedDocuments":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["invoice","creditNote","supplierInvoice","quote","proforma","salesReceipt","simpleCreditNote","purchaseOrder"],"description":"Kind of the linked document."},"id":{"type":"string","description":"Identifier of the linked document."},"amount":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Amount of this payment assigned to the document, as a decimal string."}},"required":["type","id","amount"],"additionalProperties":false},"description":"Documents the payment is assigned to; empty if it is not linked to any."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 UTC."},"updatedAt":{"type":"string","format":"date-time","description":"Last modification date in ISO 8601 UTC."}},"required":["id","direction","amount","currency","date","type","treasuryAccountId","contactId","reference","linkedDocuments","createdAt","updatedAt"],"description":"A collection or a payment recorded in treasury."},"PaymentList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PaymentDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of payment records in `data`, with its `pagination`."},"DocumentLineDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the line within the document."},"resourceType":{"type":"string","enum":["item","kit","space","vehicle","personnel","service","custom","section","type_group"],"description":"Resource type of the line. Lines of type section and type_group are presentation groupings with no associated resource."},"transactionType":{"type":"string","enum":["rental","sale"],"description":"Nature of the line: rental or sale."},"position":{"type":"integer","description":"Display position of the line within the document, starting at 0."},"itemId":{"type":["string","null"],"description":"Catalog item identifier; null if the line is not of type item."},"itemName":{"type":["string","null"],"description":"Item name as it was WHEN THE DOCUMENT WAS ISSUED. It may differ from the current item name in the catalog: the document is a snapshot."},"variantId":{"type":["string","null"],"description":"Variant identifier; null if not applicable."},"variantName":{"type":["string","null"],"description":"Variant name frozen in the snapshot; null if not applicable."},"quantity":{"type":"number","description":"Units invoiced or quoted on the line."},"orderId":{"type":["string","null"],"description":"Order the line comes from; null if it was added directly to the document."},"orderNumber":{"type":["string","null"],"description":"Number of that order; null if the line does not come from one."},"startDate":{"type":["string","null"],"format":"date-time","description":"Start of the invoiced period in ISO 8601 UTC; null if the line has no period."},"endDate":{"type":["string","null"],"format":"date-time","description":"End of the invoiced period in ISO 8601 UTC; null if the line has no period."},"rentalDays":{"type":["number","null"],"description":"Invoiced rental days; null if not applicable."},"unitPrice":{"type":["string","null"],"pattern":"^-?\\d+\\.\\d{2}$","description":"Net unit price as a decimal string \"1234.50\"; null if the line has no price of its own."},"linePrice":{"type":["string","null"],"pattern":"^-?\\d+\\.\\d{2}$","description":"Net amount of the line as a decimal string \"1234.50\"; null if not calculated."},"free":{"type":"boolean","description":"true if the line is explicitly billed at zero."},"notes":{"type":["string","null"],"description":"Line notes; null if none."}},"required":["id","resourceType","transactionType","position","itemId","itemName","variantId","variantName","quantity","orderId","orderNumber","startDate","endDate","rentalDays","unitPrice","linePrice","free","notes"],"description":"Sales document line: what was invoiced, how much and at what price."},"DocumentLineList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DocumentLineDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of document line records in `data`, with its `pagination`."},"SerializedItemDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the physical unit."},"code":{"type":"string","description":"Internal code of the unit."},"serialNumber":{"type":["string","null"],"description":"Manufacturer serial number; null if not registered."},"status":{"type":"string","description":"Current status of the unit within the inventory cycle."},"condition":{"type":["string","null"],"description":"Condition; null if not assessed."},"inventoryType":{"type":"string","description":"\"regular\" for own stock, \"temporary\" for stock brought in for a specific job."},"itemId":{"type":"string","description":"Identifier of the catalog item this unit belongs to."},"itemName":{"type":"string","description":"Name of the catalog item."},"itemSku":{"type":["string","null"],"description":"SKU of the item; null if it has none."},"variantId":{"type":["string","null"],"description":"Variant identifier; null if the item has no variants."},"variantName":{"type":["string","null"],"description":"Variant name; null if not applicable."},"currentOrderId":{"type":["string","null"],"description":"Order that holds the unit once it is prepared, picked up, sold or returned; null otherwise. A unit that is only reserved on an order is not committed yet: it stays available and this is null (the reservation is read from the serial numbers of the order line)."},"currentOrderNumber":{"type":["string","null"],"description":"Number of that order; null if the unit is free."},"projectId":{"type":["string","null"],"description":"Project associated with the current order; null if not applicable."},"contactId":{"type":["string","null"],"description":"Customer of the current order; null if not applicable."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 UTC."},"updatedAt":{"type":"string","format":"date-time","description":"Last modification date in ISO 8601 UTC."}},"required":["id","code","serialNumber","status","condition","inventoryType","itemId","itemName","itemSku","variantId","variantName","currentOrderId","currentOrderNumber","projectId","contactId","createdAt","updatedAt"],"description":"Specific physical unit of an item, with its serial number and where it is."},"SerializedItemList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SerializedItemDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of serialized item records in `data`, with its `pagination`."},"SerializedItemDetailDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the physical unit."},"code":{"type":"string","description":"Internal code of the unit."},"serialNumber":{"type":["string","null"],"description":"Manufacturer serial number; null if not registered."},"status":{"type":"string","description":"Current status of the unit within the inventory cycle."},"itemId":{"type":"string","description":"Identifier of the catalog item this unit belongs to."},"itemName":{"type":"string","description":"Name of the catalog item."},"itemSku":{"type":["string","null"],"description":"SKU of the item; null if it has none."},"itemCollectionName":{"type":["string","null"],"description":"Name of the collection of the item; null if it is in none."},"createdAt":{"type":["string","null"],"format":"date-time","description":"Creation date in ISO 8601 UTC; null if not recorded."},"updatedAt":{"type":["string","null"],"format":"date-time","description":"Last modification date in ISO 8601 UTC; null if not recorded."}},"required":["id","code","serialNumber","status","itemId","itemName","itemSku","itemCollectionName","createdAt","updatedAt"],"additionalProperties":false,"description":"The serialized item in full, as returned by the API."},"SerializedItemDetailResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SerializedItemDetailDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the serialized item detail in `data`."},"SpaceDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique space identifier."},"name":{"type":"string","description":"Space name."},"internalReference":{"type":["string","null"],"description":"Internal reference of the space, useful for matching with external systems; null if it has none."},"isWarehouse":{"type":"boolean","description":"true if the space is a warehouse that manages stock and can be the main warehouse of an order; false if it is a rentable space."},"collectionId":{"type":["string","null"],"description":"Identifier of the collection it belongs to; null if it is in none."},"collectionName":{"type":["string","null"],"description":"Full collection path, for example \"Estudios > Fotografía\"; null if not applicable."},"building":{"type":["string","null"],"description":"Building it is located in; null if not applicable."},"floor":{"type":["number","null"],"description":"Floor it is located on; null if not applicable."},"location":{"type":"object","properties":{"address":{"type":["string","null"],"description":"Postal address; null if not recorded."},"city":{"type":["string","null"],"description":"Municipality; null if not recorded."},"postalCode":{"type":["string","null"],"description":"Postal code; null if not recorded."},"country":{"type":["string","null"],"description":"Country; null if not recorded."},"lat":{"type":["number","null"],"description":"Latitude in decimal degrees; null if not geolocated."},"lng":{"type":["number","null"],"description":"Longitude in decimal degrees; null if not geolocated."}},"required":["address","city","postalCode","country","lat","lng"],"description":"Physical location of the space."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 UTC."},"updatedAt":{"type":"string","format":"date-time","description":"Last modification date in ISO 8601 UTC."}},"required":["id","name","internalReference","isWarehouse","collectionId","collectionName","building","floor","location","createdAt","updatedAt"],"description":"Warehouse or rentable space of the account."},"SpaceList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SpaceDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of space records in `data`, with its `pagination`."},"SpaceDetailDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique space identifier."},"name":{"type":"string","description":"Space name."},"internalReference":{"type":["string","null"],"description":"Internal reference of the space, useful for matching with external systems; null if it has none."},"isWarehouse":{"type":"boolean","description":"true if the space is a warehouse that manages stock and can be the main warehouse of an order; false if it is a rentable space."},"collectionId":{"type":["string","null"],"description":"Identifier of the collection it belongs to; null if it is in none."},"collectionName":{"type":["string","null"],"description":"Full collection path, for example \"Estudios > Fotografía\"; null if not applicable."},"building":{"type":["string","null"],"description":"Building it is located in; null if not applicable."},"floor":{"type":["number","null"],"description":"Floor it is located on; null if not applicable."},"location":{"type":"object","properties":{"address":{"type":["string","null"],"description":"Postal address; null if not recorded."},"city":{"type":["string","null"],"description":"Municipality; null if not recorded."},"postalCode":{"type":["string","null"],"description":"Postal code; null if not recorded."},"country":{"type":["string","null"],"description":"Country; null if not recorded."},"lat":{"type":["number","null"],"description":"Latitude in decimal degrees; null if not geolocated."},"lng":{"type":["number","null"],"description":"Longitude in decimal degrees; null if not geolocated."}},"required":["address","city","postalCode","country","lat","lng"],"description":"Physical location of the space."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 UTC."},"updatedAt":{"type":"string","format":"date-time","description":"Last modification date in ISO 8601 UTC."},"description":{"type":["string","null"],"description":"Space description; null if it has none."},"capacity":{"type":["number","null"],"description":"Capacity in people; null if not defined."},"area":{"type":["number","null"],"description":"Area in square metres; null if not defined."},"dimensions":{"type":["string","null"],"description":"Dimensions as free text; null if not defined."},"amenities":{"type":"array","items":{"type":"string"},"description":"Additional services available (wifi, projector...)."},"equipments":{"type":"array","items":{"type":"string"},"description":"Fixed equipment available in the space."},"pricingSettings":{"type":["object","null"],"properties":{"type":{"type":["string","null"],"enum":["periodPrice","fixedPrice","pricingStructure",null],"description":"Pricing mode; null if not configured."},"price":{"type":["string","null"],"pattern":"^-?\\d+\\.\\d{2}$","description":"Base rental price as a decimal string; null if not configured."},"period":{"type":["string","null"],"enum":["hour","day","week","month",null],"description":"Period unit of the price; null if not configured."}},"required":["type","price","period"],"additionalProperties":false,"description":"Rental pricing of the space; null if not configured. The same fields that PATCH /pricing accepts."},"insuranceEnabled":{"type":"boolean","description":"Whether the space allows insurance."},"discountEnabled":{"type":"boolean","description":"Whether the space allows a discount."},"depositValue":{"type":["string","null"],"pattern":"^-?\\d+\\.\\d{2}$","description":"Security deposit amount as a decimal string; null if not set."},"bufferBefore":{"type":["number","null"],"description":"Time buffer reserved BEFORE the rental; null if none."},"bufferBeforeUnit":{"type":["string","null"],"enum":["hour","day",null],"description":"Unit of the preceding buffer; null if none."},"bufferAfter":{"type":["number","null"],"description":"Time buffer reserved AFTER the rental; null if none."},"bufferAfterUnit":{"type":["string","null"],"enum":["hour","day",null],"description":"Unit of the following buffer; null if none."},"customFields":{"type":"object","additionalProperties":{},"description":"Custom field values by custom field identifier; the definitions are in /api/v1/custom-fields."}},"required":["id","name","internalReference","isWarehouse","collectionId","collectionName","building","floor","location","createdAt","updatedAt","description","capacity","area","dimensions","amenities","equipments","pricingSettings","insuranceEnabled","discountEnabled","depositValue","bufferBefore","bufferBeforeUnit","bufferAfter","bufferAfterUnit","customFields"],"description":"Detail of a warehouse or rentable space."},"SpaceDetailResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SpaceDetailDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the space detail in `data`."},"SpaceUpdateBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Space name."},"internalReference":{"type":["string","null"],"description":"Internal reference, unique within the account; null clears it."},"description":{"type":["string","null"],"description":"Space description; null clears it."},"building":{"type":["string","null"],"description":"Building the space belongs to; null clears it."},"location":{"type":"object","properties":{"address":{"type":"string","description":"Street and number."},"city":{"type":"string","description":"City."},"postalCode":{"type":"string","description":"Postal code."},"country":{"type":"string","description":"Country."},"lat":{"type":"number","description":"Latitude in decimal degrees."},"lng":{"type":"number","description":"Longitude in decimal degrees."}},"required":["lat","lng"],"additionalProperties":false,"description":"Space location. Coordinates are required if the object is sent."},"capacity":{"type":["number","null"],"minimum":0,"description":"Maximum capacity in people; null clears it."},"dimensions":{"type":["string","null"],"description":"Dimensions as free text; null clears it."},"area":{"type":["number","null"],"minimum":0,"description":"Area in square metres; null clears it."},"floor":{"type":["number","null"],"description":"Floor the space is on; null clears it."},"isWarehouse":{"type":"boolean","description":"true if it is a warehouse that manages stock; false if it is a rentable space."},"tags":{"type":"array","items":{"type":"string"},"description":"Tags by identifier or by name; a name that does not exist CREATES the tag. Replaces the whole list."},"collectionId":{"type":["string","null"],"minLength":1,"description":"Collection the space belongs to; null removes it from any collection."}},"additionalProperties":false,"description":"Body of the request that updates this space."},"SpaceAmenitiesBody":{"type":"object","properties":{"commodities":{"type":"array","items":{"type":"string"},"description":"Services offered with the space (wifi, 24/7 access, parking...). REPLACES the whole list."},"amenities":{"type":"array","items":{"type":"string"},"description":"Physical equipment delivered with the space (projector, whiteboard, sound...). REPLACES the whole list."}},"required":["commodities","amenities"],"additionalProperties":false,"description":"Body of the request that replaces the commodities and amenities of a space."},"SpacePricingBody":{"type":"object","properties":{"pricingSettings":{"type":["object","null"],"properties":{"type":{"type":"string","enum":["periodPrice","fixedPrice","pricingStructure"],"description":"Pricing mode."},"price":{"type":"string","pattern":"^\\d{1,13}(\\.\\d{1,2})?$","description":"Base rental price, as a decimal string."},"period":{"type":"string","enum":["hour","day","week","month"],"description":"Period unit of the price."}},"required":["type","price","period"],"additionalProperties":false,"description":"Rental pricing of the space, the three fields together; null clears it."},"insuranceEnabled":{"type":"boolean","description":"Whether the space allows insurance."},"depositValue":{"type":["string","null"],"pattern":"^\\d{1,13}(\\.\\d{1,2})?$","description":"Security deposit amount, as a decimal string; null clears it."},"discountEnabled":{"type":"boolean","description":"Whether the space allows a discount."},"bufferBefore":{"type":["number","null"],"minimum":0,"description":"Time buffer reserved BEFORE the rental; null clears it together with its unit."},"bufferBeforeUnit":{"type":["string","null"],"enum":["hour","day",null],"description":"Unit of the preceding buffer; null only together with `bufferBefore: null`."},"bufferAfter":{"type":["number","null"],"minimum":0,"description":"Time buffer reserved AFTER the rental; null clears it together with its unit."},"bufferAfterUnit":{"type":["string","null"],"enum":["hour","day",null],"description":"Unit of the following buffer; null only together with `bufferAfter: null`."}},"additionalProperties":false,"description":"Body of the request that updates the pricing of a space: price settings, deposit, insurance, discount and buffers. Only the fields sent change."},"RepairTicketDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique ticket identifier."},"number":{"type":"string","description":"Ticket number, for example \"RT-2026-0001\"."},"date":{"type":"string","format":"date-time","description":"Issue date in ISO 8601 UTC."},"status":{"type":"string","enum":["draft","sent","partially_converted","fully_invoiced","closed"],"description":"Status of the ticket in its lifecycle."},"orderId":{"type":["string","null"],"description":"Identifier of the order it comes from; null if it was created standalone."},"orderNumber":{"type":["string","null"],"description":"Number of the order it comes from; null if it was created standalone."},"contactId":{"type":["string","null"],"description":"Identifier of the responsible client; null if none has been assigned."},"contactName":{"type":["string","null"],"description":"Name of the responsible client; null if not resolved."},"subTotal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Sum of the lines before taxes, as a decimal string \"1234.50\"."},"taxTotal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Tax total, as a decimal string \"1234.50\"."},"total":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Total including taxes, as a decimal string \"1234.50\"."},"totalLines":{"type":"integer","description":"Number of lines in the ticket."},"notes":{"type":["string","null"],"description":"General remarks; null if it has none."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 UTC."},"updatedAt":{"type":"string","format":"date-time","description":"Last modification date in ISO 8601 UTC."}},"required":["id","number","date","status","orderId","orderNumber","contactId","contactName","subTotal","taxTotal","total","totalLines","notes","createdAt","updatedAt"],"description":"Repair ticket: what broke and what is quoted to fix it."},"RepairTicketList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/RepairTicketDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of repair ticket records in `data`, with its `pagination`."},"RepairTicketDetailDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique ticket identifier."},"number":{"type":"string","description":"Ticket number, for example \"RT-2026-0001\"."},"date":{"type":"string","format":"date-time","description":"Issue date in ISO 8601 UTC."},"status":{"type":"string","enum":["draft","sent","partially_converted","fully_invoiced","closed"],"description":"Status of the ticket in its lifecycle."},"orderId":{"type":["string","null"],"description":"Identifier of the order it comes from; null if it was created standalone."},"orderNumber":{"type":["string","null"],"description":"Number of the order it comes from; null if it was created standalone."},"contactId":{"type":["string","null"],"description":"Identifier of the responsible client; null if none has been assigned."},"contactName":{"type":["string","null"],"description":"Name of the responsible client; null if not resolved."},"subTotal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Sum of the lines before taxes, as a decimal string \"1234.50\"."},"taxTotal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Tax total, as a decimal string \"1234.50\"."},"total":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Total including taxes, as a decimal string \"1234.50\"."},"totalLines":{"type":"integer","description":"Number of lines in the ticket."},"notes":{"type":["string","null"],"description":"General remarks; null if it has none."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 UTC."},"updatedAt":{"type":"string","format":"date-time","description":"Last modification date in ISO 8601 UTC."},"projectId":{"type":["string","null"],"description":"Identifier of the associated project; null if it has none."},"lines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique line identifier."},"entityType":{"type":["string","null"],"enum":["item","serializedItem","space","kit",null],"description":"Type of element being repaired: item, serializedItem (a specific unit), space or kit; null for a free line (a service, a charge)."},"entityId":{"type":["string","null"],"description":"Identifier of the element being repaired; null if it is a free line."},"entityName":{"type":["string","null"],"description":"Name of the element being repaired; null if not resolved."},"description":{"type":"string","description":"What needs to be repaired."},"diagnosis":{"type":["string","null"],"description":"Technical diagnosis; null if none has been recorded."},"quantity":{"type":["number","null"],"description":"Affected units; null if not applicable."},"unitPrice":{"type":["string","null"],"pattern":"^-?\\d+\\.\\d{2}$","description":"NET unit price quoted to the client, as a decimal string \"1234.50\". It is not the repair cost: that one is not published. null if the line has no price."},"incidentId":{"type":["string","null"],"description":"Identifier of the incident that originated this line; null if it does not come from one."},"notes":{"type":["string","null"],"description":"Line notes; null if it has none."}},"required":["id","entityType","entityId","entityName","description","diagnosis","quantity","unitPrice","incidentId","notes"],"description":"Line of a repair ticket: what is repaired and at what price for the client."},"description":"Ticket lines."},"sourceIncidentIds":{"type":"array","items":{"type":"string"},"description":"Identifiers of the incidents that originated the ticket."},"customFields":{"type":"object","additionalProperties":{},"description":"Custom field values by custom field identifier; the definitions are in /api/v1/custom-fields."}},"required":["id","number","date","status","orderId","orderNumber","contactId","contactName","subTotal","taxTotal","total","totalLines","notes","createdAt","updatedAt","projectId","lines","sourceIncidentIds","customFields"],"description":"Detail of a repair ticket, with its lines."},"RepairTicketDetailResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/RepairTicketDetailDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the repair ticket detail in `data`."},"VehicleDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique vehicle identifier."},"name":{"type":"string","description":"Vehicle name."},"status":{"type":"string","enum":["active","maintenance","inactive"],"description":"Operational status: active (available), maintenance (in the workshop) or inactive (out of service)."},"registrationNumber":{"type":["string","null"],"description":"Registration number; null if not recorded."},"seats":{"type":["number","null"],"description":"Seats, including the driver seat; null if not recorded."},"payloadKg":{"type":["number","null"],"description":"Payload in kilograms; null if not recorded."},"inspectionDate":{"type":["string","null"],"format":"date-time","description":"Date of the next technical inspection in ISO 8601 UTC; null if not recorded."},"collectionId":{"type":["string","null"],"description":"Identifier of the collection it belongs to; null if it is in none."},"collectionName":{"type":["string","null"],"description":"Collection path; null if not applicable."},"showInPlanner":{"type":"boolean","description":"true if it appears in the planner of the account."},"createdAt":{"type":["string","null"],"format":"date-time","description":"Creation date in ISO 8601 UTC; null if not recorded."},"updatedAt":{"type":["string","null"],"format":"date-time","description":"Last modification date in ISO 8601 UTC; null if not recorded."}},"required":["id","name","status","registrationNumber","seats","payloadKg","inspectionDate","collectionId","collectionName","showInPlanner","createdAt","updatedAt"],"description":"Fleet vehicle. Does not include operating costs or pricing settings."},"VehicleList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/VehicleDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of vehicle records in `data`, with its `pagination`."},"VehicleResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/VehicleDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the vehicle in `data`."},"VehicleCreateBody":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":200,"description":"Vehicle name."},"registrationNumber":{"type":"string","maxLength":30,"description":"Registration number."},"description":{"type":"string","maxLength":2000,"description":"Vehicle description or notes."},"collectionId":{"type":"string","minLength":1,"description":"Collection it belongs to."},"tags":{"type":"array","items":{"type":"string","maxLength":100},"maxItems":50,"description":"Tags by name; a name that does not exist CREATES the tag."},"seats":{"type":"integer","minimum":0,"description":"Number of seats."}},"required":["name"],"additionalProperties":false,"description":"Body of the request that creates this vehicle."},"VehicleUpdateBody":{"type":"object","properties":{"name":{"type":"string","minLength":2,"description":"Vehicle name."},"description":{"type":"string","description":"Vehicle description or notes."},"status":{"type":"string","enum":["active","maintenance","inactive"],"description":"Vehicle status."},"registrationNumber":{"type":["string","null"],"description":"Registration number; null clears it."},"seats":{"type":["integer","null"],"minimum":0,"description":"Number of seats; null clears it."},"payloadKg":{"type":["number","null"],"minimum":0,"description":"Payload in kilograms; null clears it."},"dimensions":{"type":"object","properties":{"lengthCm":{"type":"number","minimum":0,"description":"Length of the cargo space in cm."},"widthCm":{"type":"number","minimum":0,"description":"Width of the cargo space in cm."},"heightCm":{"type":"number","minimum":0,"description":"Height of the cargo space in cm."},"surfaceAreaM2":{"type":"number","minimum":0,"description":"Cargo area in m²."}},"additionalProperties":false,"description":"Cargo space dimensions."},"collectionId":{"type":["string","null"],"minLength":1,"description":"Collection it belongs to; null removes it from any collection."},"tags":{"type":"array","items":{"type":"string"},"description":"Tags by identifier or name. Replaces the whole list."},"showInPlanner":{"type":"boolean","description":"Whether the vehicle appears as an assignable resource in the planner."},"inspectionDate":{"type":["string","null"],"format":"date-time","description":"Date of the next technical inspection, in ISO 8601 with offset; null clears it."}},"additionalProperties":false,"description":"Body of the request that updates this vehicle."},"StaffMemberDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique staff member identifier."},"fullName":{"type":"string","description":"Full name."},"staffType":{"type":"string","enum":["employee","freelancer","contractor"],"description":"Staff member type."},"collectionId":{"type":["string","null"],"description":"Identifier of the collection it belongs to; null if it is in none."},"collectionName":{"type":["string","null"],"description":"Collection path it belongs to; null if not applicable."},"hasDrivingLicense":{"type":"boolean","description":"true if they hold a driving licence."},"showInPlanner":{"type":"boolean","description":"true if they appear in the planner of the account."},"externalRef":{"type":["string","null"],"description":"External reference for matching with third-party systems; null if it has none."},"createdAt":{"type":["string","null"],"format":"date-time","description":"Creation date in ISO 8601 UTC; null if not recorded."},"updatedAt":{"type":["string","null"],"format":"date-time","description":"Last modification date in ISO 8601 UTC; null if not recorded."}},"required":["id","fullName","staffType","collectionId","collectionName","hasDrivingLicense","showInPlanner","externalRef","createdAt","updatedAt"],"description":"Staff member, with the minimum projection needed for planning. Does NOT include contact, identity, employment or platform access data: see the resource documentation."},"StaffMemberList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StaffMemberDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of staff member records in `data`, with its `pagination`."},"StaffMemberResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StaffMemberDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the staff member in `data`."},"StaffMemberCreateBody":{"type":"object","properties":{"fullName":{"type":"string","minLength":2,"maxLength":200,"description":"Full name."},"staffType":{"type":"string","enum":["employee","freelancer","contractor"],"description":"Engagement type with the company."},"collectionId":{"type":"string","minLength":1,"description":"Collection it belongs to."},"tags":{"type":"array","items":{"type":"string","maxLength":100},"maxItems":50,"description":"Tags by name; a name that does not exist CREATES the tag."},"hasDrivingLicense":{"type":"boolean","description":"Whether they hold a driving licence. It is the field that decides who can drive a vehicle."}},"required":["fullName"],"additionalProperties":false,"description":"Body of the request that creates this staff member."},"StaffUpdateBody":{"type":"object","properties":{"fullName":{"type":"string","minLength":2,"description":"Full name."},"staffType":{"type":"string","enum":["employee","freelancer","contractor"],"description":"Engagement type with the company."},"collectionId":{"type":["string","null"],"minLength":1,"description":"Collection it belongs to; null removes them from any collection."},"tags":{"type":"array","items":{"type":"string"},"description":"Tags by identifier or name. Replaces the whole list."},"hasDrivingLicense":{"type":"boolean","description":"Whether they hold a driving licence."},"showInPlanner":{"type":"boolean","description":"Whether they appear as an assignable resource in the planner."},"externalRef":{"type":["string","null"],"description":"Reference in the integrator system. It is the field used to match the two records; null clears it."}},"additionalProperties":false,"description":"Body of the request that updates this staff."},"SubrentDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique subrent identifier."},"type":{"type":"string","enum":["bulk","serialized"],"description":"bulk if it is a quantity of a bulk item, serialized if it is a specific unit."},"status":{"type":"string","enum":["pending","active","completed","cancelled"],"description":"Subrent status."},"itemId":{"type":"string","description":"Identifier of the subrented item."},"itemName":{"type":"string","description":"Name of the subrented item."},"itemSku":{"type":["string","null"],"description":"Item SKU; null if it has none."},"quantity":{"type":["number","null"],"description":"Subrented units; null if it is a specific unit."},"serializedItemId":{"type":["string","null"],"description":"Identifier of the specific unit; null if bulk."},"serializedItemCode":{"type":["string","null"],"description":"Code of the specific unit; null if bulk."},"providerId":{"type":["string","null"],"description":"Identifier of the supplier that lends the material; null if not decided yet."},"providerName":{"type":["string","null"],"description":"Supplier name; null if not decided yet."},"needResolved":{"type":"boolean","description":"true if the need is already covered, that is, if the supplier and material are confirmed."},"startDate":{"type":["string","null"],"format":"date-time","description":"Start of the required period in ISO 8601 UTC; null if not set."},"endDate":{"type":["string","null"],"format":"date-time","description":"End of the required period in ISO 8601 UTC; null if not set."},"pickupDate":{"type":["string","null"],"format":"date-time","description":"Pickup date from the supplier in ISO 8601 UTC; null if not set."},"returnDate":{"type":["string","null"],"format":"date-time","description":"Return date to the supplier in ISO 8601 UTC; null if not set."},"orderId":{"type":["string","null"],"description":"Order that motivates the subrent; null if it has none."},"projectId":{"type":["string","null"],"description":"Associated project; null if it has none."},"purchaseOrderId":{"type":["string","null"],"description":"Purchase order that formalizes it; null if none has been issued."},"spaceId":{"type":["string","null"],"description":"Warehouse where the material is received; null if not applicable."},"notes":{"type":["string","null"],"description":"Subrent notes; null if it has none."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 UTC."},"updatedAt":{"type":"string","format":"date-time","description":"Last modification date in ISO 8601 UTC."}},"required":["id","type","status","itemId","itemName","itemSku","quantity","serializedItemId","serializedItemCode","providerId","providerName","needResolved","startDate","endDate","pickupDate","returnDate","orderId","projectId","purchaseOrderId","spaceId","notes","createdAt","updatedAt"],"description":"Material rented from another company to cover a job. It does NOT include what is paid to the supplier: crossing it with the sale price of the line would give the exact margin."},"SubrentList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SubrentDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of subrent records in `data`, with its `pagination`."},"SubrentResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SubrentDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the subrent in `data`."},"PurchaseOrderDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique purchase order identifier."},"poNumber":{"type":["string","null"],"description":"Purchase order number; null while it is a draft."},"status":{"type":"string","enum":["draft","pending","completed","cancelled"],"description":"Purchase order status."},"type":{"type":"string","enum":["subrental","stock_purchase","resale_purchase","consumable_purchase","technician","transport","repair","consignment"],"description":"Purchase order type."},"isDraft":{"type":"boolean","description":"true if the purchase order is still a draft."},"poDate":{"type":["string","null"],"format":"date-time","description":"Purchase order date in ISO 8601 UTC; null if not set."},"supplierId":{"type":["string","null"],"description":"Supplier identifier; null while a draft has no supplier. Resolve it against /api/v1/contacts."},"reference":{"type":["string","null"],"description":"Free-form reference of the purchase order; null if it has none."},"currency":{"type":"string","description":"Currency of the purchase order, as an ISO 4217 code."},"subTotal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Subtotal before discounts and taxes, as a decimal string \"1234.50\"."},"discountTotal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Discount total, as a decimal string \"1234.50\"."},"taxesPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Tax total, as a decimal string \"1234.50\"."},"netPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Taxable base, as a decimal string \"1234.50\"."},"grossPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Total including taxes, as a decimal string \"1234.50\"."},"totalPaid":{"type":["string","null"],"pattern":"^-?\\d+\\.\\d{2}$","description":"Amount already paid, as a decimal string \"1234.50\"; null if no payment has been recorded."},"orderId":{"type":["string","null"],"description":"Associated rental order; null if it has none."},"orderNumber":{"type":["string","null"],"description":"Number of that order; null if it has none."},"projectId":{"type":["string","null"],"description":"Associated project; null if it has none."},"repairTicketId":{"type":["string","null"],"description":"Repair ticket that originated the purchase; null if it does not come from one."},"notes":{"type":["string","null"],"description":"Purchase order notes; null if it has none."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 UTC."},"updatedAt":{"type":"string","format":"date-time","description":"Last modification date in ISO 8601 UTC."}},"required":["id","poNumber","status","type","isDraft","poDate","supplierId","reference","currency","subTotal","discountTotal","taxesPrice","netPrice","grossPrice","totalPaid","orderId","orderNumber","projectId","repairTicketId","notes","createdAt","updatedAt"],"description":"Purchase order to a supplier. The amounts are COST amounts, because the object is a purchase. The lines are not published, so the expense cannot be attributed to a specific item of a rental."},"PurchaseOrderList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PurchaseOrderDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of purchase order records in `data`, with its `pagination`."},"PurchaseOrderResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PurchaseOrderDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the purchase order in `data`."},"ContractDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique contract identifier."},"contractNumber":{"type":["string","null"],"description":"Contract number, for example \"C260001\"; null while it is a draft."},"status":{"type":"string","enum":["draft","validated","voided"],"description":"Document status."},"operativeStatus":{"type":"string","enum":["pending","signed","cancelled"],"description":"Signature status."},"signed":{"type":"boolean","description":"true if the contract is recorded as signed. This is what decides whether the equipment can go out."},"signedAt":{"type":["string","null"],"format":"date-time","description":"Signature date in ISO 8601 UTC; null if not signed."},"contactId":{"type":["string","null"],"description":"Customer identifier; null in drafts without a customer."},"orderId":{"type":["string","null"],"description":"Associated order; null if it has none."},"orderNumber":{"type":["string","null"],"description":"Number of the associated order; null if it has none."},"projectId":{"type":["string","null"],"description":"Associated project; null if it has none."},"contractDate":{"type":["string","null"],"format":"date-time","description":"Contract date in ISO 8601 UTC; null if not set."},"startDate":{"type":["string","null"],"format":"date-time","description":"Start of validity in ISO 8601 UTC; null if not applicable."},"endDate":{"type":["string","null"],"format":"date-time","description":"End of validity in ISO 8601 UTC; null if not applicable."},"grossPrice":{"type":["string","null"],"pattern":"^-?\\d+\\.\\d{2}$","description":"Total amount including taxes as a decimal string \"1234.50\"; null if not applicable."},"createdAt":{"type":["string","null"],"format":"date-time","description":"Creation date in ISO 8601 UTC; null if not recorded."},"updatedAt":{"type":["string","null"],"format":"date-time","description":"Last modification date in ISO 8601 UTC; null if not recorded."}},"required":["id","contractNumber","status","operativeStatus","signed","signedAt","contactId","orderId","orderNumber","projectId","contractDate","startDate","endDate","grossPrice","createdAt","updatedAt"],"description":"Rental contract. Does not include the legal clauses or the tax snapshot of the customer."},"ContractList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ContractDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of contract records in `data`, with its `pagination`."},"ContractResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ContractDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the contract in `data`."},"ProjectTypeDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the project type."},"name":{"type":"string","description":"Project type name."},"color":{"type":"string","description":"Associated color, in hexadecimal, as rendered in the interface."},"description":{"type":["string","null"],"description":"Type description; null if it has none."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 UTC."},"updatedAt":{"type":"string","format":"date-time","description":"Last modification date in ISO 8601 UTC."}},"required":["id","name","color","description","createdAt","updatedAt"],"description":"Project type. Use it to resolve the `projectTypeId` filter of /api/v1/projects."},"ProjectTypeItems":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ProjectTypeDto"}},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the project type records in `data`."},"ResourceAvailability":{"type":"object","properties":{"resourceId":{"type":"string","description":"Identifier of the queried resource."},"name":{"type":"string","description":"Name of the resource."},"available":{"type":"boolean","description":"true if there are no commitments, absences or blocking incidents in the window."},"commitments":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["order","internal_service","unavailability","incident"],"description":"order (a line of an order), internal_service (an internal service, not tied to an order), unavailability (a declared absence) or incident (a blocking incident)."},"orderId":{"type":["string","null"],"description":"Order that occupies the resource; null unless kind is order."},"orderNumber":{"type":["string","null"],"description":"Number of that order; null unless kind is order."},"label":{"type":"string","description":"What occupies the resource: the service name for orders; a generic label for internal services, absences and incidents (their title or private reason is never exposed)."},"startDate":{"type":"string","format":"date-time","description":"Start of the commitment in ISO 8601 UTC."},"endDate":{"type":"string","format":"date-time","description":"End of the commitment in ISO 8601 UTC."}},"required":["kind","orderId","orderNumber","label","startDate","endDate"],"additionalProperties":false,"description":"Commitment that occupies the resource within the queried window."},"description":"Everything that occupies the resource within the window, typed. Empty when the resource is free."}},"required":["resourceId","name","available","commitments"],"additionalProperties":false,"description":"Availability of a scheduled resource within a time window."},"ResourceAvailabilityErrorEntry":{"type":"object","properties":{"resourceId":{"type":"string","description":"Identifier the request asked for."},"error":{"type":"object","properties":{"code":{"type":"string","enum":["not_found"],"description":"The resource does not exist in the account."},"message":{"type":"string","description":"Human-readable explanation."}},"required":["code","message"],"additionalProperties":false}},"required":["resourceId","error"],"additionalProperties":false,"description":"The requested resource does not exist in the account: the entry carries an error instead of a result."},"ResourceAvailabilityEntryDto":{"anyOf":[{"$ref":"#/components/schemas/ResourceAvailability"},{"$ref":"#/components/schemas/ResourceAvailabilityErrorEntry"}],"description":"Availability of one resource, or a per-item error when a requested identifier does not exist."},"ResourceAvailabilityEntryItems":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ResourceAvailabilityEntryDto"}},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the resource availability entry records in `data`."},"StaffAvailabilityBody":{"type":"object","properties":{"startDate":{"type":"string","format":"date-time","description":"Start of the window to check (ISO 8601 with offset)."},"endDate":{"type":"string","format":"date-time","description":"End of the window to check (ISO 8601 with offset); must be later than startDate."},"tags":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Only resources carrying ALL these tag identifiers."},"collectionId":{"type":"string","minLength":1,"maxLength":100,"description":"Only resources in this collection."},"search":{"type":"string","minLength":1,"maxLength":200,"description":"Free-text search on the name."},"staffIds":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":100,"description":"Restrict the answer to these staff members (1-100). An identifier that does not exist comes back as a per-item error."}},"required":["startDate","endDate"],"additionalProperties":false,"description":"Body of the request that checks which staff members are available in a date range, optionally filtered by tags, collection, search or ids."},"VehicleAvailabilityBody":{"type":"object","properties":{"startDate":{"type":"string","format":"date-time","description":"Start of the window to check (ISO 8601 with offset)."},"endDate":{"type":"string","format":"date-time","description":"End of the window to check (ISO 8601 with offset); must be later than startDate."},"tags":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Only resources carrying ALL these tag identifiers."},"collectionId":{"type":"string","minLength":1,"maxLength":100,"description":"Only resources in this collection."},"search":{"type":"string","minLength":1,"maxLength":200,"description":"Free-text search on the name."},"vehicleIds":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":100,"description":"Restrict the answer to these vehicles (1-100). An identifier that does not exist comes back as a per-item error."}},"required":["startDate","endDate"],"additionalProperties":false,"description":"Body of the request that checks which vehicles are available in a date range, optionally filtered by tags, collection, search or ids."},"CustomFieldDefinitionDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the definition. It is the one used when writing a value."},"name":{"type":"string","description":"Display name of the field."},"dataType":{"type":"string","enum":["text","multitext","dropdown","checkbox","radio","date","contact","item","space","staff_member","vehicle"],"description":"Data type the field accepts."},"description":{"type":["string","null"],"description":"Field description; null if it has none."},"options":{"type":"array","items":{"type":"string"},"description":"Allowed values when the field is a dropdown. Empty for the other types."},"applyAt":{"type":"array","items":{"type":"string","enum":["order","item","space","contact","project","kit","orderTemplate","repairTicket","serializedItem","vehicle","staff","service","purchaseOrder","incident","opportunity","document","all"],"description":"Entity the field can be used on."},"description":"Entities the field can be used on."},"showOn":{"type":"array","items":{"type":"string","enum":["quote","proforma","invoice","contract","packing_slip","purchase_order","repair_ticket","all"],"description":"Document type the field is printed on."},"description":"Documents the field is printed on."},"isActive":{"type":"boolean","description":"true if the definition is active and can be used."},"createdAt":{"type":["string","null"],"format":"date-time","description":"Creation date in ISO 8601 UTC; null if not recorded."},"updatedAt":{"type":["string","null"],"format":"date-time","description":"Last modification date in ISO 8601 UTC; null if not recorded."}},"required":["id","name","dataType","description","options","applyAt","showOn","isActive","createdAt","updatedAt"],"description":"DEFINITION of a custom field of the account: its identifier, the type it admits and the values it accepts. It is not the value assigned to any entity."},"CustomFieldDefinitionItems":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CustomFieldDefinitionDto"}},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the custom field definition records in `data`."},"TagDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the tag."},"name":{"type":"string","description":"Tag name."},"count":{"type":"integer","description":"Number of entities the tag is assigned to."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 UTC."},"updatedAt":{"type":"string","format":"date-time","description":"Last modification date in ISO 8601 UTC."}},"required":["id","name","count","createdAt","updatedAt"],"description":"Tag of the account, with how many entities use it."},"TagItems":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TagDto"}},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the tag records in `data`."},"TagCreateResultDto":{"type":"object","properties":{"id":{"type":"string","description":"Tag identifier."},"name":{"type":"string","description":"Tag name."},"assigned":{"type":"boolean","description":"true if the tag was also assigned to the entity given in the body."}},"required":["id","name","assigned"],"description":"Newly created tag."},"TagCreateResultResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TagCreateResultDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the tag create result in `data`."},"TagCreateBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Tag name."},"entityId":{"type":"string","description":"Entity to assign the tag to in the same step. Requires `entityType`."},"entityType":{"type":"string","enum":["item","contact","order","space","project","kit","serializedItem","vehicle","staff","service","purchaseOrder","incident","repairTicket","opportunity","contract","invoice","creditNote","salesReceipt","simpleCreditNote","supplierInvoice"],"description":"Type of that entity. Requires `entityId`."}},"required":["name"],"additionalProperties":false,"description":"Body of the request that creates this tag."},"TagAssignmentResultDto":{"type":"object","properties":{"tagId":{"type":"string","description":"Tag identifier."},"entityId":{"type":"string","description":"Entity identifier."},"assigned":{"type":"boolean","description":"true after assigning, false after removing."}},"required":["tagId","entityId","assigned"],"description":"Link between a tag and an entity."},"TagAssignmentResultResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TagAssignmentResultDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the tag assignment result in `data`."},"TagAssignmentBody":{"type":"object","properties":{"entityId":{"type":"string","minLength":1,"description":"Entity the tag is assigned to or removed from."},"entityType":{"type":"string","enum":["item","contact","order","space","project","kit","serializedItem","vehicle","staff","service","purchaseOrder","incident","repairTicket","opportunity","contract","invoice","creditNote","salesReceipt","simpleCreditNote","supplierInvoice"],"description":"Type of that entity."}},"required":["entityId","entityType"],"additionalProperties":false,"description":"Body of the request that assigns a tag to an entity or removes it from it."},"KitDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the kit."},"name":{"type":"string","description":"Kit name."},"description":{"type":["string","null"],"description":"Kit description; null if it has none."},"image":{"type":["string","null"],"description":"URL of the main image; null if it has none."},"collectionId":{"type":["string","null"],"description":"Collection it belongs to; null if it is in none."},"collectionName":{"type":["string","null"],"description":"Full path of the collection; null if it is in none."},"tags":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the tag."},"name":{"type":"string","description":"Tag name."}},"required":["id","name"],"additionalProperties":false},"description":"Kit tags, with their identifier and name."},"components":{"type":"array","items":{"type":"object","properties":{"itemId":{"type":"string","description":"Identifier of the item; read it in /api/v1/items/{itemId}."},"itemName":{"type":"string","description":"Item name, as recorded when it was added to the kit."},"variantId":{"type":["string","null"],"description":"Variant of the item, if one was chosen; null otherwise."},"variantName":{"type":["string","null"],"description":"Name of that variant; null if none."},"quantity":{"type":"number","description":"How many units of the item the kit includes."},"position":{"type":["number","null"],"description":"Display order inside the kit (0-based); null if not set."}},"required":["itemId","itemName","variantId","variantName","quantity","position"],"additionalProperties":false,"description":"One item of the kit, with its quantity."},"description":"Items that make up the kit, in display order."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 UTC."},"updatedAt":{"type":"string","format":"date-time","description":"Last modification date in ISO 8601 UTC."}},"required":["id","name","description","image","collectionId","collectionName","tags","components","createdAt","updatedAt"],"description":"Named group of items that go out together."},"KitList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/KitDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of kit records in `data`, with its `pagination`."},"KitResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/KitDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the kit in `data`."},"KitCreateBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Kit name."},"description":{"type":"string","description":"Kit description."},"image":{"type":"string","description":"URL of the main image."},"collectionId":{"type":"string","description":"Collection it belongs to."},"tags":{"type":"array","items":{"type":"string"},"description":"Tags by NAME; a name that does not exist is created."}},"required":["name"],"additionalProperties":false,"description":"Body of the request that creates this kit."},"KitUpdateBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Kit name."},"description":{"type":["string","null"],"description":"Kit description; null clears it."},"image":{"type":["string","null"],"description":"URL of the main image; null clears it."},"collectionId":{"type":["string","null"],"minLength":1,"description":"Collection it belongs to; null removes it from any collection."},"tags":{"type":"array","items":{"type":"string"},"description":"Tags by NAME; a name that does not exist is created."}},"additionalProperties":false,"description":"Body of the request that updates this kit."},"CollectionDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the collection."},"name":{"type":"string","description":"Collection name."},"path":{"type":"string","description":"Full name from the top-level collection, with the levels joined by \" > \"."},"entityType":{"type":"string","enum":["item","space","vehicle","staff","service"],"description":"What the collection groups: item, space, vehicle, staff or service."},"parentId":{"type":["string","null"],"description":"Identifier of the parent collection; null for a top-level collection."},"depth":{"type":"integer","description":"Levels above it: 0 for a top-level collection, 1 for its children, and so on."},"order":{"type":"number","description":"Display order among its siblings."},"itemCount":{"type":"integer","description":"Entities directly in this collection, without counting its sub-collections."},"createdAt":{"type":["string","null"],"format":"date-time","description":"Creation date in ISO 8601 UTC; null if not recorded."},"updatedAt":{"type":["string","null"],"format":"date-time","description":"Last modification date in ISO 8601 UTC; null if not recorded."}},"required":["id","name","path","entityType","parentId","depth","order","itemCount","createdAt","updatedAt"],"description":"Node of the tree the catalog is organized by. The tree is rebuilt from `parentId`."},"CollectionList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CollectionDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of collection records in `data`, with its `pagination`."},"CollectionCreatedDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the collection."},"name":{"type":"string","description":"Collection name."},"entityType":{"type":"string","enum":["item","space","vehicle","staff","service"],"description":"What the collection groups: item, space, vehicle, staff or service."}},"required":["id","name","entityType"],"description":"Receipt of a created collection."},"CollectionCreatedResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CollectionCreatedDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the collection created in `data`."},"CollectionCreateBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Collection name."},"description":{"type":"string","description":"Collection description."},"parentCollectionId":{"type":"string","description":"Parent collection. Omit it for a top-level collection."},"icon":{"type":"string","description":"Collection icon."},"entityType":{"type":"string","enum":["item","space","vehicle","staff","service"],"description":"What the collection groups. Defaults to \"item\". It cannot be changed afterwards."}},"required":["name"],"additionalProperties":false,"description":"Body of the request that creates this collection."},"CollectionUpdateResultDto":{"type":"object","properties":{"id":{"type":"string","description":"Identifier of the updated collection."},"updated":{"type":"boolean","description":"true when the change was applied."}},"required":["id","updated"],"description":"Result of patching a collection."},"CollectionUpdateResultResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CollectionUpdateResultDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the collection update result in `data`."},"CollectionUpdateBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Collection name."},"description":{"type":"string","description":"Collection description."},"parentCollectionId":{"type":["string","null"],"description":"New parent collection; null moves it to the top level."},"icon":{"type":"string","description":"Collection icon."},"order":{"type":"number","description":"Display order among its siblings."}},"additionalProperties":false,"description":"Body of the request that updates this collection."},"ServiceDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique service identifier."},"name":{"type":"string","description":"Service name as the customer sees it."},"serviceType":{"type":"string","description":"Type: crew (personnel), fleet (vehicles) or general."},"description":{"type":["string","null"],"description":"Description; null if it has none."},"defaultQty":{"type":"integer","description":"Quantity added to an order by default."},"showInPlanner":{"type":"boolean","description":"Whether it appears as a plannable service."},"includeInPrice":{"type":"boolean","description":"Whether its amount counts towards the document total."},"collectionName":{"type":["string","null"],"description":"Path of the collection it belongs to; null if it is in none."},"tags":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the tag."},"name":{"type":"string","description":"Tag name."}},"required":["id","name"],"additionalProperties":false},"description":"Service tags, with their identifier and name."},"requirements":{"type":"array","items":{"type":"object","properties":{"requiredResourceType":{"type":"string","enum":["personnel","vehicle"],"description":"What is needed to provide it: personnel or vehicle."},"qty":{"type":"integer","minimum":1,"description":"How many are needed."},"requiredTags":{"type":"array","items":{"type":"string","maxLength":100},"maxItems":20,"description":"Tags the assigned resource must have. E.g.: \"Carné C\"."}},"required":["requiredResourceType","qty"],"additionalProperties":false},"description":"Resources needed to provide it."},"createdAt":{"type":["string","null"],"format":"date-time","description":"Creation date in ISO 8601 UTC; null if not recorded."},"updatedAt":{"type":["string","null"],"format":"date-time","description":"Last modification date in ISO 8601 UTC; null if not recorded."}},"required":["id","name","serviceType","description","defaultQty","showInPlanner","includeInPrice","collectionName","tags","requirements","createdAt","updatedAt"],"description":"Sellable line that does not come from inventory: personnel, transport, work days."},"ServiceList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ServiceDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of service records in `data`, with its `pagination`."},"ServiceResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ServiceDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the service in `data`."},"ServiceCreateBody":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":200,"description":"Service name as the customer will see it."},"serviceType":{"type":"string","enum":["crew","fleet","general"],"description":"Service type."},"description":{"type":"string","maxLength":2000,"description":"Service description."},"collectionId":{"type":"string","minLength":1,"description":"Collection it belongs to."},"tags":{"type":"array","items":{"type":"string","maxLength":100},"maxItems":50,"description":"Tags by name; one that does not exist is created."},"defaultQty":{"type":"integer","minimum":1,"description":"Quantity added to an order by default."},"showInPlanner":{"type":"boolean","description":"Whether it appears as a plannable service."},"requirements":{"type":"array","items":{"type":"object","properties":{"requiredResourceType":{"type":"string","enum":["personnel","vehicle"],"description":"What is needed to provide it: personnel or vehicle."},"qty":{"type":"integer","minimum":1,"description":"How many are needed."},"requiredTags":{"type":"array","items":{"type":"string","maxLength":100},"maxItems":20,"description":"Tags the assigned resource must have. E.g.: \"Carné C\"."}},"required":["requiredResourceType","qty"],"additionalProperties":false},"maxItems":20,"description":"Resources needed to provide it."}},"required":["name"],"additionalProperties":false,"description":"Body of the request that creates this service."},"ServiceUpdateBody":{"type":"object","properties":{"name":{"type":"string","minLength":2,"description":"Customer-facing service name."},"description":{"type":["string","null"],"description":"Service description; null clears it."},"serviceType":{"type":"string","enum":["crew","fleet","general"],"description":"Service type."},"showInPlanner":{"type":"boolean","description":"Whether it appears as a plannable service."},"defaultQty":{"type":"integer","minimum":1,"description":"Default quantity."},"breakMinutes":{"type":"integer","minimum":0,"description":"Break deducted from the work day, in minutes."},"orderInfo":{"type":"string","description":"Information printed on the order and on the delivery note."},"priceConfig":{"type":"object","properties":{"hourlyRate":{"type":"number","minimum":0,"description":"Price per hour."},"fixedPrice":{"type":"number","minimum":0,"description":"Fixed price per service."},"perKmRate":{"type":"number","minimum":0,"description":"Price per kilometre."}},"additionalProperties":false,"description":"Service rate."},"includeInPrice":{"type":"boolean","description":"Whether its amount counts towards the document total."},"distancePolicy":{"type":"string","description":"How the billable distance is calculated."},"travelTimeBefore":{"type":"integer","minimum":0,"description":"Travel time before, in minutes."},"travelTimeAfter":{"type":"integer","minimum":0,"description":"Travel time after, in minutes."},"usagePeriodPolicy":{"type":"object","properties":{"inherit":{"type":"string","enum":["order","custom"],"description":"\"order\" inherits the dates of the order; \"custom\" uses the offsets below."},"offsetBeforeMinutes":{"type":"integer","minimum":0,"description":"Minutes before the order start."},"offsetAfterMinutes":{"type":"integer","minimum":0,"description":"Minutes after the order end."}},"required":["inherit"],"additionalProperties":false,"description":"Window in which it is used."},"planningPeriodPolicy":{"type":"object","properties":{"inherit":{"type":"string","enum":["order","custom"],"description":"\"order\" inherits the dates of the order; \"custom\" uses the offsets below."},"offsetBeforeMinutes":{"type":"integer","minimum":0,"description":"Minutes before the order start."},"offsetAfterMinutes":{"type":"integer","minimum":0,"description":"Minutes after the order end."}},"required":["inherit"],"additionalProperties":false,"description":"Window in which it is planned."},"defaultExpenses":{"type":"object","properties":{"catering":{"type":"object","properties":{"price":{"type":"number","description":"What the customer is charged for this concept."}},"required":["price"],"additionalProperties":false,"description":"Meal allowances."},"travel":{"type":"object","properties":{"price":{"type":"number","description":"What the customer is charged for this concept."}},"required":["price"],"additionalProperties":false,"description":"Travel."},"accommodation":{"type":"object","properties":{"price":{"type":"number","description":"What the customer is charged for this concept."}},"required":["price"],"additionalProperties":false,"description":"Accommodation."},"other":{"type":"object","properties":{"price":{"type":"number","description":"What the customer is charged for this concept."}},"required":["price"],"additionalProperties":false,"description":"Other expenses."}},"additionalProperties":false,"description":"Expenses passed on by default. Only the price, not the cost. Merged with the stored ones: categories you omit are left unchanged, and each category keeps its stored cost."},"requirements":{"type":"array","items":{"type":"object","properties":{"requiredResourceType":{"type":"string","enum":["personnel","vehicle"],"description":"What is needed to provide it: personnel or vehicle."},"qty":{"type":"integer","minimum":1,"description":"How many are needed."},"requiredTags":{"type":"array","items":{"type":"string","maxLength":100},"maxItems":20,"description":"Tags the assigned resource must have. E.g.: \"Carné C\"."}},"required":["requiredResourceType","qty"],"additionalProperties":false},"description":"Required resources. Replaces the whole list."},"collectionId":{"type":"string","description":"Collection it belongs to."},"tags":{"type":"array","items":{"type":"string"},"description":"Tags. Replaces the whole list."},"images":{"type":"array","items":{"type":"string"},"description":"Service image URLs."}},"additionalProperties":false,"description":"Body of the request that updates this service."},"InternalServiceDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique assignment identifier."},"title":{"type":"string","description":"Assignment title."},"status":{"type":"string","description":"Status: active, completed or cancelled."},"startDate":{"type":"string","format":"date-time","description":"Start in ISO 8601 UTC."},"endDate":{"type":"string","format":"date-time","description":"End in ISO 8601 UTC."},"projectId":{"type":["string","null"],"description":"Associated project; null if not applicable."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 UTC."},"updatedAt":{"type":"string","format":"date-time","description":"Last modification date in ISO 8601 UTC."}},"required":["id","title","status","startDate","endDate","projectId","createdAt","updatedAt"],"description":"Plannable assignment not attached to an order."},"InternalServiceList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/InternalServiceDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of internal service records in `data`, with its `pagination`."},"InternalServiceResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/InternalServiceDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the internal service in `data`."},"InternalServiceCreateBody":{"type":"object","properties":{"title":{"type":"string","minLength":1,"description":"Assignment title."},"description":{"type":"string","description":"Description of what needs to be done."},"serviceId":{"type":"string","description":"Catalogue service it comes from, if it comes from one."},"serviceType":{"type":"string","enum":["crew","fleet","general"],"description":"Assignment type. Defaults to \"crew\"."},"startDate":{"type":"string","format":"date-time","description":"Start in ISO 8601 with offset."},"endDate":{"type":"string","format":"date-time","description":"End in ISO 8601 with offset. At least fifteen minutes after the start."},"projectId":{"type":"string","description":"Project it is charged to."},"assignedStaffIds":{"type":"array","items":{"type":"string"},"description":"Assigned staff."},"assignedVehicleIds":{"type":"array","items":{"type":"string"},"description":"Assigned vehicles."},"qty":{"type":"integer","minimum":1,"description":"How many units of the service."},"requirements":{"type":"array","items":{"type":"object","properties":{"requiredResourceType":{"type":"string","enum":["personnel","vehicle"],"description":"What is needed: personnel or vehicle."},"qty":{"type":"integer","minimum":1,"description":"How many are needed."}},"required":["requiredResourceType","qty"],"additionalProperties":false},"description":"Resources needed to provide it."}},"required":["title","startDate","endDate"],"additionalProperties":false,"description":"Body of the request that creates this internal service."},"InternalServiceUpdateBody":{"type":"object","properties":{"title":{"type":"string","minLength":1,"description":"Assignment title."},"description":{"type":["string","null"],"description":"Description."},"serviceId":{"type":["string","null"],"description":"Catalogue service; null unlinks it."},"serviceType":{"type":"string","enum":["crew","fleet","general"],"description":"Assignment type."},"startDate":{"type":"string","format":"date-time","description":"Start in ISO 8601 with offset."},"endDate":{"type":"string","format":"date-time","description":"End in ISO 8601 with offset."},"projectId":{"type":["string","null"],"description":"Project; null unlinks it."},"assignedStaffIds":{"type":"array","items":{"type":"string"},"description":"Assigned staff. Replaces the whole list."},"assignedVehicleIds":{"type":"array","items":{"type":"string"},"description":"Assigned vehicles. Replaces the whole list."},"qty":{"type":"integer","minimum":1,"description":"How many units of the service."},"requirements":{"type":"array","items":{"type":"object","properties":{"requiredResourceType":{"type":"string","enum":["personnel","vehicle"],"description":"What is needed: personnel or vehicle."},"qty":{"type":"integer","minimum":1,"description":"How many are needed."}},"required":["requiredResourceType","qty"],"additionalProperties":false},"description":"Required resources. Replaces the whole list."},"status":{"type":"string","enum":["active","completed","cancelled"],"description":"Assignment status."}},"additionalProperties":false,"description":"Body of the request that updates this internal service."},"PlannerServiceDto":{"type":"object","properties":{"orderServiceId":{"type":"string","description":"Service line identifier. It is the one passed when assigning."},"rowKind":{"type":"string","enum":["summary","detail"],"description":"Which row this is. A service comes as ONE `summary` row (the service itself, with `staffMemberId` and `vehicleId` always null) plus one `detail` row per person or vehicle assigned to it, all with the same `orderServiceId`. A service is covered when it has `detail` rows with an assignee, and uncovered when it only has the `summary` row."},"orderId":{"type":"string","description":"Order the service is attached to; an empty string on internal services, which belong to no order."},"orderNumber":{"type":"string","description":"Human-readable number of that order; an empty string on internal services."},"orderStatus":{"type":"string","description":"Order status."},"contactName":{"type":["string","null"],"description":"Customer of the order; null if not recorded."},"projectId":{"type":["string","null"],"description":"Associated project; null if not applicable."},"projectName":{"type":["string","null"],"description":"Project name; null if not applicable."},"serviceId":{"type":"string","description":"Catalogue service it comes from."},"serviceName":{"type":"string","description":"Service name."},"serviceType":{"type":"string","description":"Type: crew, fleet or general."},"staffMemberId":{"type":["string","null"],"description":"Assigned staff member. Only `detail` rows carry it; it is null on the `summary` row even when the service is covered."},"vehicleId":{"type":["string","null"],"description":"Assigned vehicle. Only `detail` rows carry it; it is null on the `summary` row even when the service is covered."},"startDate":{"type":"string","format":"date-time","description":"Service start in ISO 8601 UTC."},"endDate":{"type":"string","format":"date-time","description":"Service end in ISO 8601 UTC."},"status":{"type":"string","description":"Service line status."},"qty":{"type":"number","description":"How many units of the service are requested."},"taskId":{"type":["string","null"],"description":"Linked schedule task; null if there is none."},"requirements":{"type":"array","items":{"type":"object","properties":{"requiredResourceType":{"type":"string","enum":["personnel","vehicle"],"description":"What is needed: personnel or vehicle."},"qty":{"type":"number","description":"How many are needed."}},"required":["requiredResourceType","qty"],"additionalProperties":false},"description":"Resources needed to cover it."}},"required":["orderServiceId","rowKind","orderId","orderNumber","orderStatus","contactName","projectId","projectName","serviceId","serviceName","serviceType","staffMemberId","vehicleId","startDate","endDate","status","qty","taskId","requirements"],"description":"Staff or fleet service pending coverage, or already covered."},"PlannerServiceItems":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PlannerServiceDto"}},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the planner service records in `data`."},"PlannerAssignResultDto":{"type":"object","properties":{"status":{"type":"string","description":"Operation result."},"conflictCount":{"type":"number","description":"Commitments of the resource that overlap with this assignment."}},"required":["status","conflictCount"],"description":"Result of assigning a resource."},"PlannerAssignResultResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PlannerAssignResultDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the planner assign result in `data`."},"PlannerAssignmentCreateBody":{"type":"object","properties":{"orderId":{"type":"string","description":"Order the service is attached to."},"orderServiceId":{"type":"string","description":"Service line within that order. Goes with `orderId`."},"taskId":{"type":"string","description":"Schedule task to assign the resource to."},"internalServiceId":{"type":"string","description":"Internal assignment to cover."},"staffId":{"type":"string","description":"Staff member being assigned."},"vehicleId":{"type":"string","description":"Vehicle being assigned."},"role":{"type":"string","description":"Role they are assigned with. E.g.: \"Conductor\"."}},"additionalProperties":false,"description":"Body of the request that creates this planner assignment."},"PlannerUnassignResultDto":{"type":"object","properties":{"status":{"type":"string","description":"Operation result."}},"required":["status"],"description":"Result of removing a resource."},"PlannerUnassignResultResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PlannerUnassignResultDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the planner unassign result in `data`."},"PlannerAssignmentRemoveBody":{"type":"object","properties":{"orderId":{"type":"string","description":"Order the service is attached to."},"orderServiceId":{"type":"string","description":"Service line within that order."},"taskId":{"type":"string","description":"Schedule task to remove the resource from."},"internalServiceId":{"type":"string","description":"Internal assignment to remove it from."},"assignmentId":{"type":"string","description":"Identifier of the specific assignment, if you have it."},"staffId":{"type":"string","description":"Staff member being removed."},"vehicleId":{"type":"string","description":"Vehicle being removed."}},"additionalProperties":false,"description":"Body of the request that removes a resource assignment from the planner; it names the assignment or the combination that identifies it."},"ScheduleDto":{"type":"object","properties":{"projects":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"startDate":{"type":"string","format":"date-time"},"endDate":{"type":"string","format":"date-time"},"status":{"type":"string"}},"required":["id","name","startDate","endDate","status"],"additionalProperties":false},"description":"Projects that fall within the window."},"orders":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"orderNumber":{"type":"string"},"startDate":{"type":"string","format":"date-time"},"endDate":{"type":"string","format":"date-time"},"status":{"type":"string"},"contactName":{"type":["string","null"]},"projectName":{"type":["string","null"]}},"required":["id","orderNumber","startDate","endDate","status","contactName","projectName"],"additionalProperties":false},"description":"Orders that fall within the window."},"tasks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"startDate":{"type":["string","null"],"format":"date-time"},"endDate":{"type":["string","null"],"format":"date-time"},"isAllDay":{"type":"boolean"},"isCompleted":{"type":"boolean"},"type":{"type":["string","null"]},"projectId":{"type":["string","null"]},"assignedStaff":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Staff member identifier."},"fullName":{"type":"string","description":"Name shown in the schedule."}},"required":["id","fullName"],"additionalProperties":false}}},"required":["id","title","startDate","endDate","isAllDay","isCompleted","type","projectId","assignedStaff"],"additionalProperties":false},"description":"Schedule tasks. Without the contact data of whoever they are assigned to."},"internalServices":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"serviceType":{"type":"string"},"startDate":{"type":"string","format":"date-time"},"endDate":{"type":"string","format":"date-time"},"projectName":{"type":["string","null"]},"qty":{"type":"number"},"assignedStaff":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Staff member identifier."},"fullName":{"type":"string","description":"Name shown in the schedule."}},"required":["id","fullName"],"additionalProperties":false}},"assignedVehicleIds":{"type":"array","items":{"type":"string"}}},"required":["id","title","serviceType","startDate","endDate","projectName","qty","assignedStaff","assignedVehicleIds"],"additionalProperties":false},"description":"Assignments not attached to an order."},"orderServices":{"type":"array","items":{"type":"object","properties":{"orderId":{"type":"string"},"orderNumber":{"type":"string"},"serviceName":{"type":"string"},"serviceType":{"type":"string"},"startDate":{"type":"string","format":"date-time"},"endDate":{"type":"string","format":"date-time"},"contactName":{"type":["string","null"]},"projectName":{"type":["string","null"]},"qty":{"type":"number"},"assignedCount":{"type":"number"},"assignedStaff":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Staff member identifier."},"fullName":{"type":"string","description":"Name shown in the schedule."}},"required":["id","fullName"],"additionalProperties":false}}},"required":["orderId","orderNumber","serviceName","serviceType","startDate","endDate","contactName","projectName","qty","assignedCount","assignedStaff"],"additionalProperties":false},"description":"Staff and fleet services attached to an order."}},"required":["projects","orders","tasks","internalServices","orderServices"],"description":"Consolidated schedule of a date window."},"ScheduleResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ScheduleDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the schedule in `data`."},"UnavailabilityDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the unavailability."},"resourceType":{"type":"string","description":"Which resource: staff, vehicle or space."},"resourceId":{"type":"string","description":"Identifier of that resource."},"resourceName":{"type":["string","null"],"description":"Resource name; null if not recorded."},"startDate":{"type":"string","format":"date-time","description":"Start of the unavailability in ISO 8601 UTC."},"endDate":{"type":"string","format":"date-time","description":"End of the unavailability in ISO 8601 UTC."},"state":{"type":"string","description":"Declared state. This list only returns `unavailable` windows that have not ended yet, so it is always `unavailable` here; `available` and `unknown` exist as declarations but are not listed."},"absenceType":{"type":["string","null"],"description":"Absence type. Only emitted for vehicles and spaces, where it is operational; for staff it is health data and is returned as null."},"updatedAt":{"type":["string","null"],"format":"date-time","description":"Last modification in ISO 8601 UTC; null if not recorded."}},"required":["id","resourceType","resourceId","resourceName","startDate","endDate","state","absenceType","updatedAt"],"description":"Window in which a resource is NOT available."},"UnavailabilityList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/UnavailabilityDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of unavailability records in `data`, with its `pagination`."},"UnavailabilityResultDto":{"type":"object","properties":{"availability":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the unavailability."},"resourceType":{"type":"string","description":"Which resource: staff, vehicle or space."},"resourceId":{"type":"string","description":"Identifier of that resource."},"resourceName":{"type":["string","null"],"description":"Resource name; null if not recorded."},"startDate":{"type":"string","format":"date-time","description":"Start of the unavailability in ISO 8601 UTC."},"endDate":{"type":"string","format":"date-time","description":"End of the unavailability in ISO 8601 UTC."},"state":{"type":"string","description":"Declared state. This list only returns `unavailable` windows that have not ended yet, so it is always `unavailable` here; `available` and `unknown` exist as declarations but are not listed."},"absenceType":{"type":["string","null"],"description":"Absence type. Only emitted for vehicles and spaces, where it is operational; for staff it is health data and is returned as null."},"updatedAt":{"type":["string","null"],"format":"date-time","description":"Last modification in ISO 8601 UTC; null if not recorded."}},"required":["id","resourceType","resourceId","resourceName","startDate","endDate","state","absenceType","updatedAt"],"description":"The unavailability as it now stands."},"warningCount":{"type":"integer","description":"Commitments of the resource that overlap this unavailability."}},"required":["availability","warningCount"],"description":"Result of declaring or updating an unavailability."},"UnavailabilityResultResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/UnavailabilityResultDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the unavailability result in `data`."},"UnavailabilityCreateBody":{"type":"object","properties":{"resourceType":{"type":"string","enum":["staff","vehicle","space"],"description":"Which resource is declared unavailable."},"resourceId":{"type":"string","minLength":1,"description":"Identifier of that resource."},"startDate":{"type":"string","format":"date-time","description":"Start, in ISO 8601 with offset."},"endDate":{"type":"string","format":"date-time","description":"End, in ISO 8601 with offset."},"state":{"type":"string","enum":["available","unavailable","unknown"],"description":"What is declared for that window."},"absenceType":{"type":"string","enum":["vacation","sick","personal","training","maintenance","inspection","repair","reserved","academic","event","closure","other"],"description":"Absence type."},"reason":{"type":"string","maxLength":500,"description":"Reason. Stored in Filmo and NOT returned by the API."}},"required":["resourceType","resourceId","startDate","endDate","state"],"additionalProperties":false,"description":"Body of the request that creates this unavailability."},"UnavailabilityUpdateBody":{"type":"object","properties":{"action":{"type":"string","enum":["edit","finish_now"],"description":"\"edit\" corrects the unavailability; \"finish_now\" closes it right now."},"expectedUpdatedAt":{"type":"string","format":"date-time","description":"Last modification date you read. If it does not match, the request is rejected."},"startDate":{"type":"string","format":"date-time","description":"New start."},"endDate":{"type":"string","format":"date-time","description":"New end."},"absenceType":{"type":["string","null"],"enum":["vacation","sick","personal","training","maintenance","inspection","repair","reserved","academic","event","closure","other",null],"description":"New absence type; null clears it."},"reason":{"type":["string","null"],"maxLength":500,"description":"New reason; null clears it. Not returned by the API."}},"required":["action","expectedUpdatedAt"],"additionalProperties":false,"description":"Body of the request that updates this unavailability."},"IncidentDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique incident identifier."},"identifier":{"type":"string","description":"Human-readable incident number."},"title":{"type":"string","description":"Short title of the incident."},"description":{"type":["string","null"],"description":"Description; null if it has none."},"type":{"type":"string","description":"Nature: damage, loss, malfunction, cosmetic, theft or custom."},"scope":{"type":"string","enum":["item","serializedItem","space","kit","vehicle","custom"],"description":"What it affects: item, serializedItem, space, kit, vehicle or custom."},"status":{"type":"string","description":"Lifecycle status: draft, open, waiting, repairing, complete or lost."},"priority":{"type":"string","description":"Priority: urgent, high, medium, low or none."},"severity":{"type":"string","description":"Declared severity."},"blocksAvailability":{"type":"boolean","description":"true when the incident removes the material from the available pool."},"affectedQuantity":{"type":["integer","null"],"description":"Affected units in bulk stock; null when not applicable."},"itemId":{"type":["string","null"],"description":"Affected item; null if not applicable."},"serializedItemId":{"type":["string","null"],"description":"Affected physical unit; null if not applicable."},"spaceId":{"type":["string","null"],"description":"Affected space; null if not applicable."},"vehicleId":{"type":["string","null"],"description":"Affected vehicle; null if not applicable."},"orderId":{"type":["string","null"],"description":"Order in which it was detected; null if not applicable."},"projectId":{"type":["string","null"],"description":"Associated project; null if not applicable."},"dueDate":{"type":["string","null"],"format":"date-time","description":"Target resolution date in ISO 8601 UTC; null if it has none."},"commentCount":{"type":"integer","description":"Comments the incident has."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 UTC."},"updatedAt":{"type":"string","format":"date-time","description":"Last modification date in ISO 8601 UTC."}},"required":["id","identifier","title","description","type","scope","status","priority","severity","blocksAvailability","affectedQuantity","itemId","serializedItemId","spaceId","vehicleId","orderId","projectId","dueDate","commentCount","createdAt","updatedAt"],"description":"Broken, lost or malfunctioning material, with its repair status."},"IncidentList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/IncidentDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of incident records in `data`, with its `pagination`."},"IncidentResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/IncidentDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the incident in `data`."},"IncidentStatusCountsDto":{"type":"object","properties":{"draft":{"type":"integer","description":"Incidents in draft."},"open":{"type":"integer","description":"Open incidents."},"waiting":{"type":"integer","description":"Waiting incidents."},"repairing":{"type":"integer","description":"Incidents under repair."},"complete":{"type":"integer","description":"Resolved incidents."},"lost":{"type":"integer","description":"Material declared lost."}},"required":["draft","open","waiting","repairing","complete","lost"],"description":"How many incidents there are in each status. All six keys are always returned, with 0 when there are none."},"IncidentStatusCountsResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/IncidentStatusCountsDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the incident status counts in `data`."},"IncidentCreateBody":{"type":"object","properties":{"title":{"type":"string","minLength":1,"description":"Short title, the one shown in lists and cards."},"type":{"type":"string","enum":["damage","loss","malfunction","cosmetic","theft","custom"],"description":"Nature of the incident."},"scope":{"type":"string","enum":["item","serializedItem","space","kit","vehicle","custom"],"description":"What the incident affects."},"status":{"type":"string","enum":["draft","open","waiting","repairing","complete","lost"],"description":"Initial status. Defaults to \"draft\"."},"priority":{"type":"string","enum":["urgent","high","medium","low","none"],"description":"Priority. Defaults to \"none\"."},"severity":{"type":"string","enum":["low","high"],"description":"Severity. Defaults to \"low\"."},"description":{"type":"string","description":"Description of what happened."},"blocksAvailability":{"type":"boolean","description":"true removes the material from the available pool while the incident is open."},"affectedQuantity":{"type":"integer","exclusiveMinimum":0,"maximum":10000,"description":"Affected units. Required when blocking bulk stock."},"itemId":{"type":"string","description":"Affected item."},"serializedItemId":{"type":"string","description":"Specific physical unit affected."},"variantId":{"type":"string","description":"Affected item variant."},"spaceId":{"type":"string","description":"Affected space."},"vehicleId":{"type":"string","description":"Affected vehicle."},"orderId":{"type":"string","description":"Order in which it was detected."},"projectId":{"type":"string","description":"Associated project."},"contactIds":{"type":"array","items":{"type":"string"},"description":"Involved contacts (supplier, insurer, client) so they can see it."},"assigneeStaffIds":{"type":"array","items":{"type":"string"},"description":"Staff assigned to resolve it."},"subscriberIds":{"type":"array","items":{"type":"string"},"description":"Deprecated: accepted for compatibility and ignored. Incidents no longer keep a subscriber list."},"labels":{"type":"array","items":{"type":"string"},"description":"Free-form labels of the incident."},"images":{"type":"array","items":{"type":"string"},"description":"URLs of photos of the damage."},"dueDate":{"type":"string","format":"date-time","description":"Target resolution date, in ISO 8601 with offset."},"reminderEnabled":{"type":"boolean","description":"Enables the internal reminder."},"reminderDate":{"type":"string","format":"date-time","description":"Reminder date, in ISO 8601 with offset."},"parentIncidentId":{"type":"string","description":"Incident of which this one is a child."}},"required":["title","type","scope"],"additionalProperties":false,"description":"Body of the request that creates this incident."},"IncidentUpdateBody":{"type":"object","properties":{"title":{"type":"string","minLength":1,"description":"Short title."},"type":{"type":"string","enum":["damage","loss","malfunction","cosmetic","theft","custom"],"description":"Nature of the incident."},"scope":{"type":"string","enum":["item","serializedItem","space","kit","vehicle","custom"],"description":"What it affects."},"status":{"type":"string","enum":["draft","open","waiting","repairing","complete","lost"],"description":"Lifecycle status."},"priority":{"type":"string","enum":["urgent","high","medium","low","none"],"description":"Priority."},"severity":{"type":"string","enum":["low","high"],"description":"Severity."},"repairType":{"type":["string","null"],"enum":["internal","external",null],"description":"Whether the team repairs it or an external workshop does."},"description":{"type":["string","null"],"description":"Description."},"blocksAvailability":{"type":"boolean","description":"Whether it removes the material from the pool."},"affectedQuantity":{"type":["integer","null"],"exclusiveMinimum":0,"maximum":10000,"description":"Affected units."},"itemId":{"type":["string","null"],"description":"Affected item; null unlinks it."},"serializedItemId":{"type":["string","null"],"description":"Physical unit; null unlinks it."},"variantId":{"type":["string","null"],"description":"Variant; null unlinks it."},"spaceId":{"type":["string","null"],"description":"Space; null unlinks it."},"vehicleId":{"type":["string","null"],"description":"Vehicle; null unlinks it."},"orderId":{"type":["string","null"],"description":"Order; null unlinks it."},"projectId":{"type":["string","null"],"description":"Project; null unlinks it."},"contactIds":{"type":"array","items":{"type":"string"},"description":"Involved contacts. Replaces the list."},"assigneeStaffIds":{"type":"array","items":{"type":"string"},"description":"Assigned staff. Replaces the list."},"subscriberIds":{"type":"array","items":{"type":"string"},"description":"Deprecated: accepted for compatibility and ignored. Incidents no longer keep a subscriber list."},"labels":{"type":"array","items":{"type":"string"},"description":"Labels. Replaces the list."},"images":{"type":"array","items":{"type":"string"},"description":"Photos of the damage. Replaces the list."},"relatedIncidentIds":{"type":"array","items":{"type":"string"},"description":"Related incidents."},"blockedByIncidentIds":{"type":"array","items":{"type":"string"},"description":"Incidents that block this one."},"dueDate":{"type":["string","null"],"format":"date-time","description":"Target date, in ISO 8601 with offset; null clears it."},"estimatedResolutionDate":{"type":["string","null"],"format":"date-time","description":"Estimated resolution date, in ISO 8601 with offset; null clears it."},"actualResolutionDate":{"type":["string","null"],"format":"date-time","description":"Actual resolution date, in ISO 8601 with offset; null clears it."},"reminderEnabled":{"type":"boolean","description":"Enables the internal reminder."},"reminderDate":{"type":["string","null"],"format":"date-time","description":"Reminder date, in ISO 8601 with offset; null clears it."},"parentIncidentId":{"type":["string","null"],"description":"Parent incident; null unlinks it."}},"additionalProperties":false,"description":"Body of the request that updates this incident."},"IncidentCommentBody":{"type":"object","properties":{"text":{"type":"string","minLength":1,"description":"Comment text. Line breaks are allowed."}},"required":["text"],"additionalProperties":false,"description":"Body of the request that adds a comment to an incident."},"NoteDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the note."},"content":{"type":"string","description":"Note text."},"relatedDocumentType":{"type":["string","null"],"description":"Type of the entity the note is attached to; null if it is not attached."},"relatedDocumentId":{"type":["string","null"],"description":"Identifier of that entity; null if the note is not attached."},"subRelatedDocumentType":{"type":["string","null"],"description":"Type of the sub-entity; null if not applicable."},"subRelatedDocumentId":{"type":["string","null"],"description":"Identifier of the sub-entity; null if not applicable."},"subRelatedDocumentCode":{"type":["string","null"],"description":"Human-readable code of the sub-entity; null if not applicable."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 UTC."},"updatedAt":{"type":"string","format":"date-time","description":"Last modification date in ISO 8601 UTC."}},"required":["id","content","relatedDocumentType","relatedDocumentId","subRelatedDocumentType","subRelatedDocumentId","subRelatedDocumentCode","createdAt","updatedAt"],"description":"Note attached to an entity of the account."},"NoteList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/NoteDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of note records in `data`, with its `pagination`."},"NoteResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/NoteDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the note in `data`."},"NoteCreateBody":{"type":"object","properties":{"relatedDocumentType":{"type":"string","enum":["item","contact","order","space","kit","vehicle","staff","service","collection","project","repairTicket","purchaseOrder","supplierInvoice"],"description":"Type of the entity the note is attached to."},"relatedDocumentId":{"type":"string","minLength":1,"description":"Identifier of that entity."},"content":{"type":"string","minLength":1,"description":"Note text."},"subRelatedDocumentType":{"type":"string","enum":["serializedItem"],"description":"When the note is about a specific physical unit of the item."},"subRelatedDocumentId":{"type":"string","description":"Identifier of that physical unit. Requires `subRelatedDocumentType`."},"subRelatedDocumentCode":{"type":"string","description":"Code of the unit, so that it can be read in the note without resolving the id."},"mentionedUserIds":{"type":"array","items":{"type":"string"},"description":"Filmo users to notify. Each one receives a notification."}},"required":["relatedDocumentType","relatedDocumentId","content"],"additionalProperties":false,"description":"Body of the request that creates this note."},"TaskDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique task identifier."},"title":{"type":"string","description":"Task title."},"description":{"type":["string","null"],"description":"Task description or notes; null if it has none."},"startDate":{"type":"string","format":"date-time","description":"Start date and time in ISO 8601 with offset."},"endDate":{"type":["string","null"],"format":"date-time","description":"End date and time in ISO 8601 with offset; null if it has no defined end."},"isAllDay":{"type":"boolean","description":"Whether the task is all-day."},"isCompleted":{"type":"boolean","description":"Whether the task is completed."},"isRecurring":{"type":"boolean","description":"Whether the task is part of a recurring series."},"recurringGroupId":{"type":["string","null"],"description":"Identifier of the recurrence group it belongs to; null if it is not recurring."},"recurrencePattern":{"type":["object","null"],"properties":{"frequency":{"type":"string","enum":["daily","weekly","monthly","yearly"],"description":"Recurrence frequency: daily, weekly, monthly or yearly."},"interval":{"type":"integer","description":"Interval between repetitions according to the frequency (e.g. 2 with weekly = every two weeks)."},"endAfterOccurrences":{"type":["integer","null"],"description":"Number of repetitions after which the recurrence ends; null if it does not end by number of occurrences."},"endDate":{"type":["string","null"],"format":"date-time","description":"Date on which the recurrence ends, in ISO 8601 with offset; null if it does not end by date."}},"required":["frequency","interval","endAfterOccurrences","endDate"],"additionalProperties":false,"description":"Recurrence pattern of the task; null if it is not recurring."},"type":{"type":"string","description":"Task type (identifier of the type)."},"assignedStaffIds":{"type":"array","items":{"type":"string"},"description":"Identifiers of the staff assigned to the task."},"projectId":{"type":["string","null"],"description":"Identifier of the linked project; null if the task is not linked."},"relatedDocumentId":{"type":["string","null"],"description":"Identifier of the related document; null if it has none."},"relatedDocumentType":{"type":["string","null"],"description":"Type of the related document (contact, order, invoice, quote, project, etc.); null if it has none."},"appearance":{"type":"object","properties":{"color":{"type":"string","description":"Task color in the schedule (hexadecimal code)."},"variant":{"type":"string","enum":["primary","secondary","destructive","default"],"description":"Visual variant of the task: primary, secondary, destructive or default."}},"required":["color","variant"],"additionalProperties":false,"description":"Appearance of the task in the schedule (color and variant)."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 with offset."},"updatedAt":{"type":"string","format":"date-time","description":"Last update date in ISO 8601 with offset."}},"required":["id","title","description","startDate","endDate","isAllDay","isCompleted","isRecurring","recurringGroupId","recurrencePattern","type","assignedStaffIds","projectId","relatedDocumentId","relatedDocumentType","appearance","createdAt","updatedAt"],"additionalProperties":false,"description":"The task, as returned by the API."},"TaskList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TaskDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of task records in `data`, with its `pagination`."},"TaskResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TaskDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the task in `data`."},"TaskCreateBody":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":300,"description":"Task title. Required."},"description":{"type":"string","maxLength":5000,"description":"Task description or notes."},"startDate":{"type":"string","format":"date-time","description":"Task start date and time (ISO 8601 with offset). Required."},"endDate":{"type":"string","format":"date-time","description":"Task end date and time (ISO 8601 with offset); must be equal to or later than startDate."},"isAllDay":{"type":"boolean","default":false,"description":"Whether the task is all-day. Defaults to false."},"type":{"type":"string","minLength":1,"maxLength":100,"description":"Task type: its identifier (system types: default, delivery, return, temporaryStock; custom types: their id, see /api/v1/task-types) or its name, matched ignoring case and accents. A name that matches several custom types is rejected with 400 listing their identifiers. The task takes the color of the type. Required."},"assignedStaffIds":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"maxItems":50,"description":"Identifiers of the staff assigned to the task (max 50)."},"projectId":{"type":"string","minLength":1,"maxLength":100,"description":"Identifier of the project the task is linked to."},"relatedDocumentId":{"type":"string","minLength":1,"maxLength":100,"description":"Identifier of the related document; always goes together with relatedDocumentType."},"relatedDocumentType":{"type":"string","enum":["contact","order","item","kit","space","collection","invoice","quote","purchaseOrder","supplierInvoice","incident","repairTicket","project","vehicle","staff","service","opportunity"],"description":"Type of the related document (contact, order, item, invoice, quote, project, etc.); always goes together with relatedDocumentId."}},"required":["title","startDate","type"],"additionalProperties":false,"description":"Body of the request that creates this task."},"TaskUpdateBody":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":300,"description":"Task title."},"description":{"type":["string","null"],"maxLength":5000,"description":"Task description or notes; null clears it."},"startDate":{"type":"string","format":"date-time","description":"Task start date and time (ISO 8601 with offset)."},"endDate":{"type":["string","null"],"format":"date-time","description":"Task end date and time (ISO 8601 with offset); must be equal to or later than startDate. null clears it."},"isAllDay":{"type":"boolean","description":"Whether the task is all-day."},"isCompleted":{"type":"boolean","description":"Marks the task as completed or pending."},"type":{"type":"string","minLength":1,"maxLength":100,"description":"Task type: its identifier or its name, matched ignoring case and accents (see POST /api/v1/tasks). Changing it also changes the color of the task to that of the type."},"assignedStaffIds":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"maxItems":50,"description":"Identifiers of the staff assigned to the task (max 50); replaces the existing assignment."},"projectId":{"type":["string","null"],"minLength":1,"maxLength":100,"description":"Identifier of the linked project; null unlinks it."},"relatedDocumentId":{"type":["string","null"],"minLength":1,"maxLength":100,"description":"Identifier of the related document; always goes together with relatedDocumentType. null (with relatedDocumentType: null) unlinks it."},"relatedDocumentType":{"type":["string","null"],"enum":["contact","order","item","kit","space","collection","invoice","quote","purchaseOrder","supplierInvoice","incident","repairTicket","project","vehicle","staff","service","opportunity",null],"description":"Type of the related document; always goes together with relatedDocumentId. null (with relatedDocumentId: null) unlinks it."}},"additionalProperties":false,"description":"Body of the request that updates this task."},"TaskTypeDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the task type."},"name":{"type":"string","description":"Task type name. System types are served in Spanish; custom types carry the name given by the account."},"color":{"type":"string","description":"Color associated with the task type (hexadecimal code)."},"isSystem":{"type":"boolean","description":"Whether it is a system type (predefined) or a custom type of the account."},"isArchived":{"type":"boolean","description":"Whether the type is archived."},"tasksCount":{"type":["integer","null"],"description":"Number of tasks that use the type; null for system types (not computed)."},"createdAt":{"type":["string","null"],"format":"date-time","description":"Creation date in ISO 8601 with offset; null for system types."},"updatedAt":{"type":["string","null"],"format":"date-time","description":"Last update date in ISO 8601 with offset; null for system types."}},"required":["id","name","color","isSystem","isArchived","tasksCount","createdAt","updatedAt"],"additionalProperties":false,"description":"The task type, as returned by the API."},"TaskTypeItems":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TaskTypeDto"}},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the task type records in `data`."},"OpportunityDto":{"type":"object","properties":{"opportunityId":{"type":"string"},"identifier":{"type":"string"},"name":{"type":"string"},"status":{"type":"string","enum":["open","won","lost"]},"amount":{"type":"string"},"currency":{"type":"string"},"pipelineId":{"type":"string"},"pipelineName":{"type":"string"},"stageId":{"type":"string"},"stageName":{"type":"string"},"stageType":{"type":"string","enum":["open","won","lost"]},"effectiveProbability":{"type":"number"},"weightedAmount":{"type":"string"},"daysInStage":{"type":"integer"},"expectedCloseDate":{"type":"string","format":"date-time"},"contactName":{"type":"string"},"companyName":{"type":"string"},"ownerName":{"type":"string"},"source":{"type":"string","enum":["inbound_email","website_form","referral","cold_outreach","event","social","existing_customer","partner","other"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["opportunityId","identifier","name","status","amount","currency","pipelineId","pipelineName","stageId","stageName","stageType","effectiveProbability","weightedAmount","daysInStage","createdAt","updatedAt"],"description":"CRM opportunity: which pipeline and stage it is in, for how much, with whom and with what probability."},"OpportunityList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OpportunityDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of opportunity records in `data`, with its `pagination`."},"OpportunityDetailDto":{"type":"object","properties":{"opportunityId":{"type":"string"},"identifier":{"type":"string"},"name":{"type":"string"},"status":{"type":"string","enum":["open","won","lost"]},"amount":{"type":"string"},"currency":{"type":"string"},"pipelineId":{"type":"string"},"pipelineName":{"type":"string"},"stageId":{"type":"string"},"stageName":{"type":"string"},"stageType":{"type":"string","enum":["open","won","lost"]},"effectiveProbability":{"type":"number"},"weightedAmount":{"type":"string"},"daysInStage":{"type":"integer"},"expectedCloseDate":{"type":"string","format":"date-time"},"contactName":{"type":"string"},"companyName":{"type":"string"},"ownerName":{"type":"string"},"source":{"type":"string","enum":["inbound_email","website_form","referral","cold_outreach","event","social","existing_customer","partner","other"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"description":{"type":"string"},"version":{"type":"integer","minimum":1},"collaboratorStaffIds":{"type":"array","items":{"type":"string"}},"quoteIds":{"type":"array","items":{"type":"string"}},"stageHistory":{"type":"array","items":{"type":"object","properties":{"fromStageId":{"type":"string"},"toStageId":{"type":"string"},"toStatus":{"type":"string"},"daysInPrevStage":{"type":"integer"},"movedAt":{"type":"string","format":"date-time"},"note":{"type":"string"}},"required":["toStageId","toStatus","movedAt"]}}},"required":["opportunityId","identifier","name","status","amount","currency","pipelineId","pipelineName","stageId","stageName","stageType","effectiveProbability","weightedAmount","daysInStage","createdAt","updatedAt","version","collaboratorStaffIds","quoteIds"],"description":"Full detail of a CRM opportunity."},"OpportunityDetailResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OpportunityDetailDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the opportunity detail in `data`."},"OpportunityCreateBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200,"description":"Short name of the opportunity."},"description":{"type":"string","description":"Free-text description."},"pipelineId":{"type":"string","description":"Pipeline. If omitted, the default pipeline of the account."},"stageId":{"type":"string","description":"Initial stage. If omitted, the first stage of the pipeline."},"amount":{"type":"string","pattern":"^\\d+(\\.\\d{1,2})?$","description":"Amount as a decimal string, with at most two decimals. E.g.: \"12500.00\"."},"currency":{"type":"string","pattern":"^[A-Z]{3}$","description":"Uppercase ISO 4217 code. E.g.: \"EUR\"."},"probabilityOverride":{"type":"integer","minimum":0,"maximum":100,"description":"Own probability, as a percentage. If omitted, it inherits the probability of the stage."},"expectedCloseDate":{"type":"string","format":"date-time","description":"Expected close date, in ISO 8601 with offset."},"contactId":{"type":"string","description":"Contact (person) of the opportunity."},"companyId":{"type":"string","description":"Contact (company) of the opportunity."},"ownerStaffId":{"type":"string","description":"Sales owner."},"projectId":{"type":"string","description":"Associated project."},"source":{"type":"string","enum":["inbound_email","website_form","referral","cold_outreach","event","social","existing_customer","partner","other"],"description":"Lead source channel: inbound_email, website_form, referral, cold_outreach, event, social, existing_customer, partner or other."},"sourceDetail":{"type":"string","maxLength":200,"description":"Free-text detail of the source channel."},"utmCampaign":{"type":"string","maxLength":200,"description":"Attribution campaign."},"utmSource":{"type":"string","maxLength":200,"description":"Attribution source."},"utmMedium":{"type":"string","maxLength":200,"description":"Attribution medium."}},"required":["name"],"additionalProperties":false,"description":"Body of the request that creates this opportunity."},"OpportunityUpdateBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200,"description":"Short name."},"description":{"type":"string","description":"Free-text description."},"amount":{"type":"string","pattern":"^\\d+(\\.\\d{1,2})?$","description":"Amount as a decimal string, with at most two decimals. E.g.: \"12500.00\"."},"currency":{"type":"string","pattern":"^[A-Z]{3}$","description":"Uppercase ISO 4217 code. E.g.: \"EUR\"."},"probabilityOverride":{"type":"integer","minimum":0,"maximum":100,"description":"Own probability, as a percentage."},"expectedCloseDate":{"type":"string","format":"date-time","description":"Expected close date, in ISO 8601 with offset."},"contactId":{"type":"string","description":"Contact (person)."},"companyId":{"type":"string","description":"Contact (company)."},"ownerStaffId":{"type":"string","description":"Sales owner."},"source":{"type":"string","enum":["inbound_email","website_form","referral","cold_outreach","event","social","existing_customer","partner","other"],"description":"Lead source channel: inbound_email, website_form, referral, cold_outreach, event, social, existing_customer, partner or other."},"sourceDetail":{"type":"string","maxLength":200,"description":"Free-text detail of the channel."}},"additionalProperties":false,"description":"Body of the request that updates this opportunity."},"OpportunityMoveStageBody":{"type":"object","properties":{"toStageId":{"type":"string","minLength":1,"description":"Target stage. It has to be an open stage."}},"required":["toStageId"],"additionalProperties":false,"description":"Body of the request that moves an opportunity to another stage of its pipeline."},"OpportunityCloseBody":{"type":"object","properties":{"outcome":{"type":"string","enum":["won","lost"],"description":"Close outcome."},"toStageId":{"type":"string","description":"Target stage. If omitted, the first stage of the corresponding type."},"wonReason":{"type":"string","maxLength":500,"description":"Reason, when the outcome is \"won\"."},"lostReason":{"type":"string","enum":["price","timing","no_budget","no_decision","lost_to_competitor","no_response","duplicate","other"],"description":"Structured reason, when the outcome is \"lost\"."}},"required":["outcome"],"additionalProperties":false,"description":"Body of the request that closes an opportunity as won or lost, with the reason and, optionally, the stage it ends in."},"OpportunityLinkMeta":{"type":"object","properties":{"kind":{"type":"string","description":"What was linked: quote, order or project."},"linkedEntityId":{"type":"string","description":"Identifier of the linked entity."},"created":{"type":"boolean","description":"true if the link is new; false if it already existed."}},"required":["kind","linkedEntityId","created"],"additionalProperties":false,"description":"Additional information of the response that links an opportunity to a record."},"LinkOpportunityRecordResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OpportunityDetailDto"},"meta":{"allOf":[{"$ref":"#/components/schemas/OpportunityLinkMeta"},{"$ref":"#/components/schemas/ResponseMeta"}]}},"required":["data","meta"],"description":"Successful response: the opportunity detail in `data`."},"OpportunityLinkBody":{"type":"object","properties":{"kind":{"type":"string","enum":["quote","order","project"],"description":"What is linked to the opportunity."},"quoteId":{"type":"string","description":"Quote. Required with kind=\"quote\"."},"orderId":{"type":"string","description":"Order. Required with kind=\"order\"."},"projectId":{"type":"string","description":"Project. Required with kind=\"project\"."},"isPrimary":{"type":"boolean","description":"Only with kind=\"quote\": marks this quote as the primary one."}},"required":["kind"],"additionalProperties":false,"description":"Body of the request that links an opportunity to a quote, an order or a project."},"PipelineDto":{"type":"object","properties":{"pipelineId":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"isDefault":{"type":"boolean"},"isArchived":{"type":"boolean"},"totalOpportunities":{"type":"integer"},"totalValue":{"type":"string"},"stages":{"type":"array","items":{"type":"object","properties":{"stageId":{"type":"string"},"name":{"type":"string"},"order":{"type":"integer"},"type":{"type":"string","enum":["open","won","lost"]},"probability":{"type":"number"},"isDefault":{"type":"boolean"}},"required":["stageId","name","order","type","probability","isDefault"]}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["pipelineId","name","slug","isDefault","isArchived","stages","createdAt","updatedAt"],"description":"CRM pipeline with its ordered stages and, optionally, the count and total value of its opportunities."},"PipelineItems":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PipelineDto"}},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the pipeline records in `data`."},"PipelineResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PipelineDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the pipeline in `data`."},"PurchaseOrderUpdateBody":{"type":"object","properties":{"type":{"type":"string","enum":["subrental","stock_purchase","resale_purchase","consumable_purchase","technician","transport","repair","consignment"],"description":"Purchase order type."},"supplierId":{"type":["string","null"],"description":"Supplier of the purchase order; null leaves it without a supplier (drafts only)."},"poDate":{"type":["string","null"],"format":"date-time","description":"Issue date, in ISO 8601 with offset; null clears it."},"supplierQuoteRef":{"type":["string","null"],"maxLength":200,"description":"Reference of the supplier quote; null clears it."},"reference":{"type":["string","null"],"maxLength":200,"description":"Internal reference of the document; null clears it."},"currency":{"type":"string","minLength":3,"maxLength":3,"description":"Currency, as an ISO 4217 code."},"projectId":{"type":["string","null"],"description":"Associated project; null unlinks it."},"orderId":{"type":["string","null"],"description":"Associated rental order; null unlinks it."},"notes":{"type":["string","null"],"maxLength":5000,"description":"Notes; null clears them."}},"required":["type"],"additionalProperties":false,"description":"Body of the request that updates this purchase order."},"PurchaseOrderReceiveMeta":{"type":"object","properties":{"receivedLines":{"type":"integer","description":"Lines the call declared as received."}},"required":["receivedLines"],"additionalProperties":false,"description":"Additional information of the response that receives a purchase order."},"ReceivePurchaseOrderResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PurchaseOrderDto"},"meta":{"allOf":[{"$ref":"#/components/schemas/PurchaseOrderReceiveMeta"},{"$ref":"#/components/schemas/ResponseMeta"}]}},"required":["data","meta"],"description":"Successful response: the purchase order in `data`."},"PurchaseOrderReceiveBody":{"type":"object","properties":{"spaceId":{"type":"string","description":"Warehouse where the material comes in. Defaults to the warehouse of the account."},"lines":{"type":"array","items":{"type":"object","properties":{"lineId":{"type":"string","minLength":1,"description":"Purchase order line being received."},"receivedQuantity":{"type":"number","minimum":0,"description":"Units received for that line."},"newStockReceived":{"type":"number","minimum":0,"description":"Of those received, how many register new inventory."},"notes":{"type":"string","maxLength":1000,"description":"Reception notes."}},"required":["lineId","receivedQuantity"],"additionalProperties":false},"minItems":1,"description":"Received lines. At least one."}},"required":["lines"],"additionalProperties":false,"description":"Body of the request that declares what arrived of a purchase order, line by line, and where it is stored."},"SupplierInvoiceDto":{"type":"object","properties":{"id":{"type":"string","description":"Supplier invoice identifier."},"supplierInvoiceNumber":{"type":["string","null"],"description":"Number the supplier put on the invoice; null if it was not recorded."},"status":{"type":"string","description":"Status of the invoice within the purchasing cycle."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 UTC."},"updatedAt":{"type":"string","format":"date-time","description":"Last modification date in ISO 8601 UTC."}},"required":["id","supplierInvoiceNumber","status","createdAt","updatedAt"],"description":"Invoice received from a supplier."},"SupplierInvoiceList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SupplierInvoiceDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of supplier invoice records in `data`, with its `pagination`."},"SupplierInvoiceResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SupplierInvoiceDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the supplier invoice in `data`."},"RepairTicketCreateBody":{"type":"object","properties":{"date":{"type":"string","format":"date-time","description":"Repair ticket date, in ISO 8601 with offset. Defaults to today."},"orderId":{"type":"string","description":"Order from which the broken material returns."},"contactId":{"type":"string","description":"Client invoiced for the repair."},"lines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Existing line being modified. Omit it for a new line."},"description":{"type":"string","minLength":1,"maxLength":500,"description":"What needs to be repaired."},"diagnosis":{"type":"string","maxLength":5000,"description":"Technical diagnosis."},"entityType":{"type":["string","null"],"enum":["item","space","kit",null],"description":"Type of element being repaired: item, space or kit. null or omitted for a free line."},"entityId":{"type":"string","description":"Element being repaired."},"serializedItemId":{"type":"string","description":"Specific physical unit, when a serialized item is repaired."},"incidentId":{"type":"string","description":"Incident that originates this line."},"quantity":{"type":"number","minimum":0,"description":"Affected units. Defaults to 1."},"unitPrice":{"type":"string","pattern":"^\\d{1,13}(\\.\\d{1,2})?$","description":"Net unit price quoted to the client, as a decimal string."},"notes":{"type":"string","maxLength":2000,"description":"Line notes."}},"required":["description"],"additionalProperties":false},"minItems":1,"description":"Repair ticket lines. At least one."},"notes":{"type":"string","maxLength":5000,"description":"Repair ticket notes."},"incidentIds":{"type":"array","items":{"type":"string"},"description":"Incidents this repair ticket converts. The server ties each line to its incident."}},"required":["lines"],"additionalProperties":false,"description":"Body of the request that creates this repair ticket."},"RepairTicketUpdateBody":{"type":"object","properties":{"date":{"type":"string","format":"date-time","description":"New date, in ISO 8601 with offset."},"status":{"type":"string","enum":["draft","sent","partially_converted","fully_invoiced","closed"],"description":"New repair ticket status."},"contactId":{"type":["string","null"],"description":"New client; null unlinks it."},"orderId":{"type":["string","null"],"description":"New order; null unlinks it."},"projectId":{"type":["string","null"],"description":"New project; null unlinks it."},"lines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Existing line being modified. Omit it for a new line."},"description":{"type":"string","minLength":1,"maxLength":500,"description":"What needs to be repaired."},"diagnosis":{"type":"string","maxLength":5000,"description":"Technical diagnosis."},"entityType":{"type":["string","null"],"enum":["item","space","kit",null],"description":"Type of element being repaired: item, space or kit. null or omitted for a free line."},"entityId":{"type":"string","description":"Element being repaired."},"serializedItemId":{"type":"string","description":"Specific physical unit, when a serialized item is repaired."},"incidentId":{"type":"string","description":"Incident that originates this line."},"quantity":{"type":"number","minimum":0,"description":"Affected units. Defaults to 1."},"unitPrice":{"type":"string","pattern":"^\\d{1,13}(\\.\\d{1,2})?$","description":"Net unit price quoted to the client, as a decimal string."},"notes":{"type":"string","maxLength":2000,"description":"Line notes."}},"required":["description"],"additionalProperties":false},"description":"COMPLETE set of lines, which replaces the current one. Omit it to leave them untouched."},"notes":{"type":["string","null"],"maxLength":5000,"description":"New notes; null clears them."}},"additionalProperties":false,"description":"Body of the request that updates this repair ticket."},"TreasuryAccountDto":{"type":"object","properties":{"id":{"type":"string","description":"Treasury account identifier."},"name":{"type":"string","description":"Name by which the treasury account is recognized."},"type":{"type":"string","enum":["bank","cash","manual"],"description":"Nature of the treasury account: bank (a bank account), cash (a cash box) or manual."},"currency":{"type":"string","description":"Currency of the treasury account, as an ISO 4217 code."},"status":{"type":"string","enum":["active","needs_reauth","disconnected","archived"],"description":"Treasury account status: active, needs_reauth (the bank connection must be renewed), disconnected or archived."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 UTC."},"updatedAt":{"type":"string","format":"date-time","description":"Last modification date in ISO 8601 UTC."}},"required":["id","name","type","currency","status","createdAt","updatedAt"],"description":"Treasury account. The bank account number is NOT published: to reference the treasury account in a payment its identifier is enough."},"TreasuryAccountList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TreasuryAccountDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of treasury account records in `data`, with its `pagination`."},"TreasuryAccountResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TreasuryAccountDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the treasury account in `data`."},"PaymentResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PaymentDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the payment in `data`."},"PaymentCreateBody":{"type":"object","properties":{"direction":{"type":"string","enum":["in","out"],"description":"in for a collection from a customer, out for a payment to a supplier."},"amount":{"type":"string","pattern":"^\\d{1,13}(\\.\\d{1,2})?$","description":"Amount as a decimal string, greater than zero."},"currency":{"type":"string","minLength":3,"maxLength":3,"description":"Currency in ISO 4217. Defaults to EUR."},"date":{"type":"string","format":"date-time","description":"Payment date, in ISO 8601 with offset. Any time of today is accepted; a later day, in the time zone of the account, is rejected with 400."},"paymentMethodId":{"type":"string","minLength":1,"description":"Payment method configured in the account."},"treasuryAccountId":{"type":"string","minLength":1,"description":"Treasury account through which the money comes in or goes out."},"type":{"type":"string","enum":["normal","deposit"],"description":"\"deposit\" marks a security deposit collected from a customer: it requires direction=in (400 otherwise) and is not deducted from the order total."},"contactId":{"type":"string","description":"Customer or supplier of the payment."},"linkedDocumentType":{"type":"string","enum":["invoice","creditNote","supplierInvoice","quote","proforma","salesReceipt","simpleCreditNote","purchaseOrder"],"description":"Type of the document the payment is linked to. Goes with `linkedDocumentId`."},"linkedDocumentId":{"type":"string","description":"Document the payment is linked to. Goes with `linkedDocumentType`."},"reference":{"type":"string","maxLength":200,"description":"External reference of the payment."},"notes":{"type":"string","maxLength":2000,"description":"Notes. They are stored in Filmo and NOT returned."}},"required":["direction","amount","date","paymentMethodId","treasuryAccountId"],"additionalProperties":false,"description":"Body of the request that creates this payment."},"PaymentUpdateBody":{"type":"object","properties":{"direction":{"type":"string","enum":["in","out"],"description":"New direction of the payment."},"amount":{"type":"string","pattern":"^\\d{1,13}(\\.\\d{1,2})?$","description":"New amount as a decimal string, greater than zero. If the whole payment is assigned to a single document or order, the assignment follows the new amount. Otherwise what is assigned stays as it is and only the unassigned part changes; an amount below what is already assigned responds 409 `conflict`."},"date":{"type":"string","format":"date-time","description":"New date, in ISO 8601 with offset. Any time of today is accepted; a later day, in the time zone of the account, is rejected with 400."},"paymentMethodId":{"type":["string","null"],"description":"New payment method; null removes it."},"contactId":{"type":["string","null"],"description":"New contact; null unlinks it."},"reference":{"type":["string","null"],"maxLength":200,"description":"New external reference; null clears it."},"notes":{"type":"string","maxLength":2000,"description":"New notes. NOT returned."},"reconciled":{"type":"boolean","description":"Marks the payment as reconciled with the bank statement."}},"additionalProperties":false,"description":"Body of the request that updates this payment."},"PaymentLinkBody":{"type":"object","properties":{"linkedDocumentType":{"type":"string","enum":["invoice","creditNote","supplierInvoice","quote","proforma","salesReceipt","simpleCreditNote","purchaseOrder"],"description":"Type of the document the payment is linked to."},"linkedDocumentId":{"type":"string","minLength":1,"description":"Document the payment is linked to."}},"required":["linkedDocumentType","linkedDocumentId"],"additionalProperties":false,"description":"Body of the request that links a payment to a document, as the pair type and identifier."},"OrderCancelMeta":{"type":"object","properties":{"tasksDeleted":{"type":"integer","description":"Logistics tasks that the cancellation cancelled when releasing the order."}},"required":["tasksDeleted"],"additionalProperties":false,"description":"Additional information of the response that cancels an order."},"CancelOrderResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrderDetailDto"},"meta":{"allOf":[{"$ref":"#/components/schemas/OrderCancelMeta"},{"$ref":"#/components/schemas/ResponseMeta"}]}},"required":["data","meta"],"description":"Successful response: the order detail in `data`."},"OrderArchiveBody":{"type":"object","properties":{"archived":{"type":"boolean","description":"true removes the order from the active views; false brings it back."}},"required":["archived"],"additionalProperties":false,"description":"Body of the request that archives or restores an order."},"SerializedItemUpdateBody":{"type":"object","properties":{"code":{"type":"string","minLength":1,"maxLength":200,"description":"Internal code of the unit. It identifies the unit, so it cannot be empty."},"serialNumber":{"type":["string","null"],"maxLength":200,"description":"Manufacturer serial number; null clears it."},"status":{"type":"string","enum":["available","prepared","picked_up","returned","broken","archived","sold"],"description":"Unit status."},"active":{"type":"boolean","description":"false removes the unit from the pool without deleting it."},"orderInfo":{"type":"string","maxLength":1000,"description":"Information visible on the order and on the delivery note."},"providerReference":{"type":"string","maxLength":200,"description":"Reference by which the supplier identifies the unit."},"poNumber":{"type":"string","maxLength":200,"description":"Number of the purchase order that brought it in."},"purchaseDate":{"type":"string","format":"date-time","description":"Purchase date, in ISO 8601 with offset."},"warrantyExpiration":{"type":"string","format":"date-time","description":"Warranty end, in ISO 8601 with offset."},"spaceId":{"type":"string","description":"Warehouse where the unit is located."},"locationId":{"type":["string","null"],"description":"Location within the warehouse; null clears it."}},"additionalProperties":false,"description":"Body of the request that updates this serialized item."},"ItemAccessoriesBody":{"type":"object","properties":{"mode":{"type":"string","enum":["merge","replace"],"description":"merge (default): operations are deltas and whatever you do not name is kept. replace: the list sent is the final list and everything absent IS DELETED."},"targetItemVariantId":{"type":"string","description":"Variant of the item the accessories apply to."},"operations":{"type":"array","items":{"type":"object","properties":{"accessoryId":{"type":"string","description":"Existing accessory. Required to update or delete."},"action":{"type":"string","enum":["create","update","delete"],"description":"What to do. If omitted: with accessoryId it updates, without it it creates."},"accessory":{"type":"object","properties":{"itemId":{"type":"string","description":"Item that acts as the accessory. Omit it for a custom one."},"quantity":{"type":"integer","minimum":1,"description":"Quantity of the accessory."},"free":{"type":"boolean","description":"true if the accessory is not charged."},"default":{"type":"boolean","description":"true if it is added automatically when the item is put in an order."},"accessoryVariantId":{"type":"string","description":"Variant of the accessory."},"isCustom":{"type":"boolean","description":"true for an accessory that is not in the catalog."},"customName":{"type":"string","minLength":1,"description":"Name of the custom accessory."},"customPrice":{"type":"number","minimum":0,"description":"Unit price of the custom accessory."},"position":{"type":"integer","minimum":0,"description":"Display order."}},"required":["quantity","free","default"],"additionalProperties":false,"description":"Accessory data."}},"required":["accessory"],"additionalProperties":false},"minItems":1,"description":"Operations to apply. At least one."}},"required":["operations"],"additionalProperties":false,"description":"Body of the request that changes the accessories of an item, as deltas (`merge`) or as the final list (`replace`)."},"ItemAlternativesBody":{"type":"object","properties":{"mode":{"type":"string","enum":["merge","replace"],"description":"merge (default): operations are deltas and whatever you do not name is kept. replace: the list sent is the final list and everything absent IS DELETED."},"operations":{"type":"array","items":{"type":"object","properties":{"alternativeId":{"type":"string","description":"Existing alternative. Required to update or delete."},"action":{"type":"string","enum":["create","update","delete"],"description":"What to do. If omitted: with alternativeId it updates, without it it creates."},"alternative":{"type":"object","properties":{"itemId":{"type":"string","minLength":1,"description":"Item that serves as the alternative."},"notes":{"type":"string","maxLength":1000,"description":"When or why this alternative is valid."}},"required":["itemId"],"additionalProperties":false,"description":"Alternative data."}},"required":["alternative"],"additionalProperties":false},"minItems":1,"description":"Operations to apply. At least one."}},"required":["operations"],"additionalProperties":false,"description":"Body of the request that changes the alternative items of an item, as deltas (`merge`) or as the final list (`replace`)."},"ItemVariantUpdateBody":{"type":"object","properties":{"variantName":{"type":"string","minLength":1,"maxLength":200,"description":"Variant name."},"variantPrice":{"type":"string","pattern":"^\\d{1,13}(\\.\\d{1,2})?$","description":"Base rental price, as a decimal string."},"salePrice":{"type":["string","null"],"pattern":"^\\d{1,13}(\\.\\d{1,2})?$","description":"Sale price per unit, as a decimal string; null clears it."},"ean":{"type":["string","null"],"maxLength":64,"description":"EAN code; null clears it."}},"additionalProperties":false,"description":"Body of the request that updates this item variant."},"PlannerResourceDto":{"type":"object","properties":{"id":{"type":"string","description":"Resource identifier."},"name":{"type":"string","description":"Name by which the resource is recognised."},"type":{"type":"string","description":"Resource nature: staff or vehicle."}},"required":["id","name","type"],"description":"A resource that can cover a planner service."},"PlannerResourceItems":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PlannerResourceDto"}},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the planner resource records in `data`."},"CreditNoteDto":{"type":"object","properties":{"id":{"type":"string","description":"Credit note identifier."},"creditNoteNumber":{"type":["string","null"],"description":"Credit note number; null while it is a draft."},"status":{"type":"string","enum":["draft","validated","voided"],"description":"Document lifecycle status: draft, validated or voided (the same values the `status` filter takes)."},"issueDate":{"type":["string","null"],"format":"date-time","description":"Issue date in ISO 8601 UTC; null if not recorded."},"currency":{"type":"string","description":"Currency, as an ISO 4217 code."},"contactId":{"type":["string","null"],"description":"Contact the credit note is issued to; null if not recorded."},"invoiceId":{"type":["string","null"],"description":"Invoice this credit note rectifies; null if it is not attached to any."},"subTotal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Subtotal before discounts and taxes, as a decimal string."},"taxesPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Tax total, as a decimal string."},"netPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Taxable base, as a decimal string."},"grossPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Total including taxes, as a decimal string."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 UTC."},"updatedAt":{"type":"string","format":"date-time","description":"Last modification date in ISO 8601 UTC."}},"required":["id","creditNoteNumber","status","issueDate","currency","contactId","invoiceId","subTotal","taxesPrice","netPrice","grossPrice","createdAt","updatedAt"],"description":"Credit note: what is refunded to the customer. The signed fiscal document, the tax breakdown and the lines are not published."},"CreditNoteList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CreditNoteDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of credit note records in `data`, with its `pagination`."},"CreditNoteResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CreditNoteDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the credit note in `data`."},"ProformaDto":{"type":"object","properties":{"id":{"type":"string","description":"Proforma identifier."},"proformaNumber":{"type":["string","null"],"description":"Proforma number; null while it is a draft."},"status":{"type":"string","description":"Document lifecycle status."},"operativeStatus":{"type":["string","null"],"description":"Commercial status: pending (awaiting an answer), confirmed (accepted by the customer) or cancelled; null if not recorded."},"issueDate":{"type":["string","null"],"format":"date-time","description":"Issue date in ISO 8601 UTC; null while it has none."},"currency":{"type":"string","description":"Currency of the amounts, as an ISO 4217 code."},"contact":{"type":["object","null"],"properties":{"id":{"type":"string","description":"Contact identifier."},"name":{"type":"string","description":"Contact name."}},"required":["id","name"],"additionalProperties":false,"description":"Contact the proforma is issued to; null if not recorded."},"orderId":{"type":["string","null"],"description":"Source order of the proforma; null if it does not come from one."},"orderNumber":{"type":["string","null"],"description":"Number of that order; null if it does not come from one."},"projectId":{"type":["string","null"],"description":"Project linked to the proforma; null if none."},"subTotal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Subtotal before discounts and taxes, as a decimal string."},"discountTotal":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Total discounts, as a decimal string."},"taxesPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Tax total, as a decimal string."},"netPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Taxable base, as a decimal string."},"grossPrice":{"type":"string","pattern":"^-?\\d+\\.\\d{2}$","description":"Total including taxes, as a decimal string."},"totalPaid":{"type":["string","null"],"pattern":"^-?\\d+\\.\\d{2}$","description":"Advance payments received against the proforma, as a decimal string; null if none recorded."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 UTC."},"updatedAt":{"type":"string","format":"date-time","description":"Last modification date in ISO 8601 UTC."}},"required":["id","proformaNumber","status","operativeStatus","issueDate","currency","contact","orderId","orderNumber","projectId","subTotal","discountTotal","taxesPrice","netPrice","grossPrice","totalPaid","createdAt","updatedAt"],"description":"Proforma: the advance invoice that is not yet an invoice."},"ProformaList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ProformaDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of proforma records in `data`, with its `pagination`."},"ProformaResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ProformaDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the proforma in `data`."},"ContactsLookupResultDto":{"type":"object","properties":{"contacts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Identifier of the contact in Filmo."},"name":{"type":"string","description":"Contact name."},"contactNumber":{"type":"string","description":"Filmo contact number."}},"required":["id","name","contactNumber"]},"description":"Contacts that matched at least one reference."},"notFound":{"type":"array","items":{"type":"string"},"description":"References that did not match any contact. These are the ones to create."}},"required":["contacts","notFound"],"description":"Result of looking up contacts by external reference."},"ContactsLookupResultResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ContactsLookupResultDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the contacts lookup result in `data`."},"ContactsLookupBody":{"type":"object","properties":{"references":{"type":"array","items":{"type":"string","minLength":1},"minItems":1,"maxItems":200,"description":"External references to look up. At least one, at most 200."}},"required":["references"],"additionalProperties":false,"description":"Body of the request that says which of a list of your own references already exist as contacts and which do not. It writes nothing."},"OrderLineReturnResultDto":{"type":"object","properties":{"index":{"type":"integer","description":"Position of the element in the request array."},"id":{"type":"string","description":"Identifier of the element as it was sent."},"status":{"type":"string","enum":["returned","failed"],"description":"`returned` or `failed`."},"error":{"type":["object","null"],"properties":{"code":{"type":"string","description":"Stable error code of the element, from the same catalog as `errors[]`."},"message":{"type":"string","description":"Localized reason."}},"required":["code","message"],"additionalProperties":false,"description":"Why it failed; null when `returned`."}},"required":["index","id","status","error"],"additionalProperties":false,"description":"Result of returning one order line."},"OrderLineReturnResultItems":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OrderLineReturnResultDto"}},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the order line return result records in `data`."},"OrderLineItemsReturnBody":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"lineItemId":{"type":"string","minLength":1,"description":"Order line being returned."},"checkInQuantity":{"type":"number","minimum":1,"description":"Units being returned, at least one. It can be a partial return."},"returnCondition":{"type":"string","enum":["good","damaged","lost","needs_repair","incident"],"description":"Physical condition the material comes back in: `good`, `damaged`, `lost`, `needs_repair` or `incident`."}},"required":["lineItemId","checkInQuantity","returnCondition"],"additionalProperties":false},"minItems":1,"maxItems":500,"description":"Lines being returned. At least one, at most 500, each line at most once."},"checkedInAt":{"type":"string","format":"date-time","description":"Effective date of the return, in ISO 8601 with offset. Defaults to now."},"atomic":{"type":"boolean","default":true,"description":"All or nothing (default true): if any line cannot be returned, none is, and the response is 409 with one issue per line. With false, each order is processed on its own, the response is 207 and every element carries its own status."}},"required":["items"],"additionalProperties":false,"description":"Body of the request that registers the return of line items: which line, how many units and in what condition."},"AiAskDto":{"type":"object","properties":{"answer":{"type":"string","description":"Answer in markdown. Empty string when needsMoreContext is true."},"needsMoreContext":{"type":"boolean","description":"True when the AI finished without being able to answer and needs more context. In that case `answer` comes empty: rephrase the question with more detail instead of retrying as is."},"webSearchSources":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","description":"URL of the consulted source."},"title":{"type":"string","description":"Source title."},"favicon":{"type":"string","description":"URL of the site favicon, to render the source."}},"required":["url","title","favicon"],"additionalProperties":false},"description":"Cited web sources. Empty if web search was not requested or if none was used."}},"required":["answer","needsMoreContext","webSearchSources"],"additionalProperties":false,"description":"The ai ask, as returned by the API."},"AiAskResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AiAskDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the ai ask in `data`."},"AiAskBody":{"type":"object","properties":{"question":{"type":"string","minLength":1,"maxLength":4000,"description":"Natural-language question about the data of your account. Required."},"webSearch":{"type":"boolean","default":false,"description":"Also allows web search to answer. Defaults to false: only the data of the account is consulted."},"mode":{"type":"string","enum":["instant"],"default":"instant","description":"Answer mode. Today only \"instant\" (a single pass, no conversation). Documented so that future modes are additive."}},"required":["question"],"additionalProperties":false,"description":"Body of the request that asks a natural-language question about the data of the account."},"WorkflowDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the workflow."},"name":{"type":"string","description":"Workflow name."},"isActive":{"type":"boolean","description":"true when the workflow is active; false when it is paused."},"archivedAt":{"type":["string","null"],"format":"date-time","description":"Date it was archived in ISO 8601 UTC; null if it is not archived."},"trigger":{"type":"object","properties":{"type":{"type":["string","null"],"enum":["manual","schedule","webhook","event","signal","entity",null],"description":"How the workflow starts: manual (a person or the API runs it), schedule (cron), webhook (an incoming request), event (something happens in Filmo), signal (another workflow) or entity (run from the page of a record). Null if it has no published version."},"event":{"type":["string","null"],"description":"For `event` triggers, the Filmo event it listens to; null otherwise."},"entity":{"type":["string","null"],"description":"For `entity` triggers, the entity type it runs on; null otherwise."},"form":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Key of the field in `payload` when running the workflow."},"label":{"type":"string","description":"Label shown to the person who runs it."},"type":{"type":"object","additionalProperties":{},"description":"Declared type of the value, in the workflow type language: `{\"type\":\"string\"}`, `{\"type\":\"number\"}`, `{\"type\":\"boolean\"}`, `{\"type\":\"date\",\"mode\":\"date\"|\"datetime\"}`, `{\"type\":\"enum\",\"options\":[{\"value\",\"label\"}]}`, `{\"type\":\"shape\",\"shape\":[{\"key\",\"label\",\"value\":<type>}]}`, `{\"type\":\"list\",\"item\":<type>}`, `{\"type\":\"record\",\"value\":<type>}` or `{\"type\":\"tuple\",\"tuple\":[<type>]}`. The value sent in `payload` is validated against it."}},"required":["name","label","type"],"description":"A field of the run form."},"description":"For `manual` triggers, the run form: every field listed is REQUIRED in `payload` when calling `POST /api/v1/workflows/{workflowId}/runs`. Empty when the workflow asks nothing."}},"required":["type","event","entity","form"],"description":"How the workflow starts and, if manual, what it asks for."},"currentVersion":{"type":["object","null"],"properties":{"version":{"type":"integer","description":"Number of the published version."},"createdAt":{"type":"string","format":"date-time","description":"When it was published, in ISO 8601 UTC."}},"required":["version","createdAt"],"description":"The published version, which is the one that runs and the one the run form is read from; null when the workflow has never been saved."},"createdAt":{"type":"string","format":"date-time","description":"Creation date in ISO 8601 UTC."},"updatedAt":{"type":"string","format":"date-time","description":"Last modification date in ISO 8601 UTC."}},"required":["id","name","isActive","archivedAt","trigger","currentVersion","createdAt","updatedAt"],"description":"Automation of the account. Does not include its definition."},"WorkflowList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WorkflowDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of workflow records in `data`, with its `pagination`."},"WorkflowRunCreatedDto":{"type":"object","properties":{"runId":{"type":"string","description":"Identifier of the queued run."},"state":{"type":"string","enum":["queued","running","waiting","paused","completed","failed","cancelled"],"description":"Initial state of the run. When just queued it is `queued`."}},"required":["runId","state"],"description":"Receipt of a queued run."},"WorkflowRunCreatedResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/WorkflowRunCreatedDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the workflow run created in `data`."},"WorkflowRunCreateBody":{"type":"object","properties":{"payload":{"type":"object","additionalProperties":{},"description":"Values of the run form of the workflow, by field name. If the workflow declares fields they are REQUIRED and are validated against its published version: if any is missing the request responds 400 and nothing is queued. If it declares none, it is ignored."}},"additionalProperties":false,"description":"Body of the request that creates this workflow run."},"OrderUpdateBody":{"type":"object","properties":{"contactId":{"type":"string","minLength":1,"maxLength":100,"description":"Identifier of the order customer. It must belong to the account of the API key."},"projectId":{"type":["string","null"],"minLength":1,"maxLength":100,"description":"Project the order is assigned to; null unlinks it (standalone order)."},"startDate":{"type":"string","format":"date-time","description":"Rental start (ISO 8601 with offset)."},"endDate":{"type":"string","format":"date-time","description":"Rental end (ISO 8601 with offset); it must be later than startDate."}},"additionalProperties":false,"description":"Body of the request that updates this order."},"OrderReserveMeta":{"type":"object","properties":{"tasksCreated":{"type":"integer","description":"Delivery and return tasks that the reservation created."}},"required":["tasksCreated"],"additionalProperties":false,"description":"Additional information of the response that reserves an order."},"ReserveOrderResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrderDetailDto"},"meta":{"allOf":[{"$ref":"#/components/schemas/OrderReserveMeta"},{"$ref":"#/components/schemas/ResponseMeta"}]}},"required":["data","meta"],"description":"Successful response: the order detail in `data`."},"OrderUnreserveMeta":{"type":"object","properties":{"tasksDeleted":{"type":"integer","description":"Delivery and return tasks that were deleted when the reservation was removed."}},"required":["tasksDeleted"],"additionalProperties":false,"description":"Additional information of the response that removes the reservation of an order."},"UnreserveOrderResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrderDetailDto"},"meta":{"allOf":[{"$ref":"#/components/schemas/OrderUnreserveMeta"},{"$ref":"#/components/schemas/ResponseMeta"}]}},"required":["data","meta"],"description":"Successful response: the order detail in `data`."},"ProjectUpdateBody":{"type":"object","properties":{"name":{"type":"string","minLength":3,"maxLength":200,"description":"Project name. At least three characters, as the domain requires."},"startDate":{"type":"string","format":"date-time","description":"Project start (ISO 8601 with offset)."},"endDate":{"type":"string","format":"date-time","description":"Project end (ISO 8601 with offset). It cannot be earlier than startDate; the same instant is a one-day project."},"contactId":{"type":"string","minLength":1,"maxLength":100,"description":"Project customer. It must belong to the account of the API key."},"projectTypeId":{"type":["string","null"],"minLength":1,"maxLength":100,"description":"Project type; resolve it against /api/v1/project-types. null clears it."},"externalReference":{"type":["string","null"],"maxLength":200,"description":"Free-form reference to match the project with an external system; null clears it."},"location":{"type":"object","properties":{"name":{"type":"string","maxLength":200,"description":"Name of the place, for example \"Main stage\"."},"address":{"type":"string","maxLength":500,"description":"Street address."},"city":{"type":"string","maxLength":200,"description":"City."},"postalCode":{"type":"string","maxLength":20,"description":"Postal code."},"province":{"type":"string","maxLength":200,"description":"Province or region."},"country":{"type":"string","maxLength":200,"description":"Country."},"lat":{"type":"number","minimum":-90,"maximum":90,"description":"Latitude in decimal degrees."},"lng":{"type":"number","minimum":-180,"maximum":180,"description":"Longitude in decimal degrees."}},"additionalProperties":false,"description":"Physical location of the project (a stage, a client site). Only the fields sent are recorded."},"color":{"type":["string","null"],"maxLength":40,"description":"Color of the project card (for example \"#3b82f6\"); null clears it."}},"additionalProperties":false,"description":"Body of the request that updates this project."},"InvoiceVoidBody":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":500,"description":"Reason for voiding. It is stored on the invoice and in its history."}},"required":["reason"],"additionalProperties":false,"description":"Body of the request that voids an invoice; the reason is required and is kept."},"InvoiceExternalUpsertBody":{"type":"object","properties":{"invoiceNumber":{"type":"string","minLength":1,"maxLength":60,"description":"Invoice number exactly as issued by the source system."},"invoiceDate":{"type":"string","format":"date","description":"Issue date."},"dueDate":{"type":"string","format":"date","description":"Due date."},"currency":{"type":"string","minLength":3,"maxLength":3,"default":"EUR","description":"ISO 4217 currency."},"contactId":{"type":"string","minLength":1,"maxLength":128,"description":"Filmo contact identifier."},"contactTaxId":{"type":"string","minLength":1,"maxLength":40,"description":"Customer tax ID, when its Filmo identifier is unknown."},"contactName":{"type":"string","minLength":1,"maxLength":200,"description":"Exact customer name, as a last resort."},"lines":{"type":"array","items":{"type":"object","properties":{"description":{"type":"string","minLength":1,"maxLength":500,"description":"Line description."},"quantity":{"type":"string","pattern":"^-?\\d{1,13}(\\.\\d{1,6})?$","description":"Quantity."},"unitPrice":{"type":"string","pattern":"^-?\\d{1,13}(\\.\\d{1,6})?$","description":"Unit price before taxes."},"discountPercent":{"type":"string","pattern":"^-?\\d{1,13}(\\.\\d{1,6})?$","description":"Line discount as a percentage (0-100)."},"taxType":{"type":"string","description":"Filmo tax type (e.g. IVA_21). When missing it is inferred from taxRate."},"taxRate":{"type":"string","pattern":"^-?\\d{1,13}(\\.\\d{1,6})?$","description":"Tax percentage of the line (e.g. \"21\"). Required when taxType is missing."}},"required":["description","quantity","unitPrice"],"additionalProperties":false},"minItems":1,"maxItems":500,"description":"Invoice lines."},"subTotal":{"type":"string","pattern":"^-?\\d{1,13}(\\.\\d{1,6})?$","description":"Taxable base according to the source system (checked against the lines)."},"taxTotal":{"type":"string","pattern":"^-?\\d{1,13}(\\.\\d{1,6})?$","description":"Tax total according to the source system."},"total":{"type":"string","pattern":"^-?\\d{1,13}(\\.\\d{1,6})?$","description":"Total according to the source system."},"externalStatus":{"type":"string","enum":["issued","voided"],"default":"issued","description":"issued, or voided in the source system."},"voidReason":{"type":"string","maxLength":500,"description":"Reason the source system voided it."},"paymentStatus":{"type":"string","enum":["unpaid","partially_paid","paid","overpaid"],"description":"Payment status according to the source system."},"totalPaid":{"type":"string","pattern":"^-?\\d{1,13}(\\.\\d{1,6})?$","description":"Amount collected according to the source system."},"originUrl":{"type":"string","maxLength":2048,"format":"uri","description":"Link to the document in the source system (https)."},"originFileUrl":{"type":"string","maxLength":2048,"format":"uri","description":"Original PDF issued by the source system (https)."},"notes":{"type":"string","maxLength":2000,"description":"Internal notes."}},"required":["invoiceNumber","invoiceDate","lines"],"additionalProperties":false,"description":"Body of the request that creates or updates the read-only mirror of an invoice issued by another system, with its lines and declared totals."},"CreditNoteVoidBody":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":500,"description":"Reason for voiding. It is stored on the credit note and in its history."}},"required":["reason"],"additionalProperties":false,"description":"Body of the request that voids a credit note; the reason is required and is kept."},"ProformaStatusBody":{"type":"object","properties":{"status":{"type":"string","enum":["pending","confirmed","cancelled"],"description":"New commercial status: pending (awaiting an answer), confirmed (accepted by the customer) or cancelled (rejected or cancelled)."},"notes":{"type":"string","maxLength":1000,"description":"Note stored in the document history alongside the status change."}},"required":["status"],"additionalProperties":false,"description":"Body of the request that changes the status of a proforma invoice."},"QuoteStatusBody":{"type":"object","properties":{"status":{"type":"string","enum":["pending","confirmed","cancelled"],"description":"New commercial status of the active version: pending (awaiting an answer), confirmed (accepted; the other versions become superseded) or cancelled (rejected or cancelled)."},"notes":{"type":"string","maxLength":1000,"description":"Note stored in the quote history alongside the status change."}},"required":["status"],"additionalProperties":false,"description":"Body of the request that changes the status of a quote."},"ContractSignBody":{"type":"object","properties":{"signedVia":{"type":"string","enum":["manual","portal"],"default":"manual","description":"How the signature was recorded: manual (internal record) or portal (the customer signed in the portal)."}},"additionalProperties":false,"description":"Body of the request that records the signature of a contract and how it was signed."},"ContractVoidBody":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":500,"description":"Void reason. It is stored in the contract and in its history."}},"required":["reason"],"additionalProperties":false,"description":"Body of the request that voids a contract; the reason is required and is kept."},"ContractCancelBody":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":500,"description":"Cancellation reason, which is kept in the contract history."}},"additionalProperties":false,"description":"Body of the request that cancels a contract, with an optional reason."},"SupplierInvoiceVoidBody":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":500,"description":"Reason for voiding. It is stored on the invoice and in its history."}},"required":["reason"],"additionalProperties":false,"description":"Body of the request that voids a received invoice; the reason is required and is kept."},"SubrentUpdateBody":{"type":"object","properties":{"status":{"type":"string","enum":["pending","active","completed","cancelled"],"description":"New subrent status."},"startDate":{"type":["string","null"],"format":"date-time","description":"Start of the subrent (ISO 8601 with offset); null clears it."},"endDate":{"type":["string","null"],"format":"date-time","description":"End of the subrent (ISO 8601 with offset); null clears it."},"needResolved":{"type":"boolean","description":"true when the material need that motivated the subrent is already covered."},"purchaseOrderId":{"type":["string","null"],"minLength":1,"description":"Purchase order the subrent is linked to; null unlinks it."},"linkQuantity":{"type":"integer","exclusiveMinimum":0,"description":"Quantity linked to the purchase order. If it is lower than the subrent quantity, the record is split: the original keeps this quantity and a new one is created with the rest."},"notes":{"type":["string","null"],"description":"Subrent notes; null clears them."}},"additionalProperties":false,"description":"Body of the request that updates this subrent."},"AccountDto":{"type":"object","properties":{"name":{"type":"string","description":"Name of the account."},"timezone":{"type":"string","description":"IANA timezone of the business, the one bare days in filters are read in."},"currency":{"type":"string","description":"ISO 4217 currency of the account; documents may carry their own."},"country":{"type":"string","description":"ISO 3166-1 alpha-2 country of the business."},"language":{"type":"string","description":"Default language of error messages for this key (BCP 47), unless Accept-Language says otherwise."},"addons":{"type":"array","items":{"type":"string","enum":["platform","user-seat","connected-account","extra-tax-cif","qr-codes","incidence","purchases","activity-log","custom-fields","profitability","web-builder","crm","consignments","email-calendar","sales-documents","internal-bookings","internal-communication","advanced-user-permissions","ai-pack-25k","ai-pack-55k","ai-pack-115k"]},"description":"Ids of the add-ons the account has access to today. A resource behind an add-on not listed here responds 402."},"trial":{"type":"object","properties":{"active":{"type":"boolean","description":"true while the trial of the account lasts: every add-on is unlocked."},"endsAt":{"type":["string","null"],"format":"date-time","description":"End of the trial in ISO 8601 UTC; null if none."}},"required":["active","endsAt"],"description":"Trial period of the account."},"apiKey":{"type":"object","properties":{"id":{"type":"string","description":"Identifier of the API key that made the request."},"name":{"type":"string","description":"Name given to the key when it was created."},"scopes":{"type":"array","items":{"type":"string"},"description":"Scopes granted to the key, the ones its requests can use."}},"required":["id","name","scopes"],"description":"The key that made the request. Never its secret."},"rateLimits":{"type":"object","properties":{"global":{"type":"object","properties":{"perMinute":{"type":"integer"}},"required":["perMinute"],"description":"Requests per minute across the whole API."},"availability":{"type":"object","properties":{"perMinute":{"type":"integer"}},"required":["perMinute"],"description":"Requests per minute of the availability checks, counted apart."}},"required":["global","availability"],"description":"Usage limits of the key, the ones the RateLimit-* headers report."},"api":{"type":"object","properties":{"version":{"type":"string","description":"Version of the public API contract."},"docsUrl":{"type":"string","description":"Where the documentation of this version lives."}},"required":["version","docsUrl"],"description":"The contract this account is served with."}},"required":["name","timezone","currency","country","language","addons","trial","apiKey","rateLimits","api"],"description":"The account that made the request, its key and its usage limits."},"AccountResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AccountDto"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data"],"description":"Successful response: the account in `data`."},"PaymentMethodDto":{"type":"object","properties":{"id":{"type":"string","description":"Payment method identifier. It is what `paymentMethodId` expects when recording a payment."},"name":{"type":"string","description":"Name of the payment method, as shown on documents."},"type":{"type":"string","enum":["bank_transfer","card","cash","other","sepa_direct_debit"],"description":"Kind of payment method: bank_transfer, card, cash, other or sepa_direct_debit."},"isSystem":{"type":"boolean","description":"true for the methods Filmo provides to every account; false for the ones the account created."},"isDefault":{"type":"boolean","description":"true for the method preselected when creating a document."},"isArchived":{"type":"boolean","description":"true when the method is no longer offered; it is kept for the documents that already use it."},"createdAt":{"type":["string","null"],"format":"date-time","description":"Creation date in ISO 8601 UTC; null if not recorded."},"updatedAt":{"type":["string","null"],"format":"date-time","description":"Last modification date in ISO 8601 UTC; null if not recorded."}},"required":["id","name","type","isSystem","isDefault","isArchived","createdAt","updatedAt"],"description":"Payment method configured in the account. It carries no payment instructions or bank details."},"PaymentMethodList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PaymentMethodDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of payment method records in `data`, with its `pagination`."},"UserDto":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the user. It is the value other resources carry in `createdBy`, `mentionedUserIds` and the like."},"name":{"type":"string","description":"Display name."},"email":{"type":"string","description":"Email the person signs in with."},"role":{"type":"object","properties":{"id":{"type":"string","description":"Identifier of the role: owner, super-admin, admin, a predefined role or `custom`."},"name":{"type":"string","description":"Name of the role, in the language of the account."}},"required":["id","name"],"description":"Role in this account."},"isAdmin":{"type":"boolean","description":"true when the role administers the account."},"status":{"type":"string","enum":["active","pending","inactive"],"description":"Access status: active, pending (invited, not yet accepted) or inactive."},"staffMemberId":{"type":["string","null"],"description":"Identifier of the staff member this user is linked to (see /api/v1/staff); null if none."},"createdAt":{"type":["string","null"],"format":"date-time","description":"Date the user account was created in ISO 8601 UTC; null for an invitation not yet accepted."},"updatedAt":{"type":["string","null"],"format":"date-time","description":"Last modification date of the user account in ISO 8601 UTC; null for an invitation not yet accepted."}},"required":["id","name","email","role","isAdmin","status","staffMemberId","createdAt","updatedAt"],"description":"A person with access to the account, with the role they hold in it."},"UserList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/UserDto"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"meta":{"$ref":"#/components/schemas/ResponseMeta"}},"required":["data","pagination"],"description":"Successful response: one page of user records in `data`, with its `pagination`."}},"parameters":{}},"paths":{"/api/v1/contacts":{"get":{"operationId":"listContacts","tags":["Contacts"],"summary":"List contacts","description":"Returns the contacts (customers and suppliers) visible to the key, cursor-paginated. Tenancy inherited from the parent account: a billing account also sees the contacts of its parent account.\n\n**Required scope:** `contacts:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"contacts:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdOn","in":"query"},{"schema":{"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdAfter","in":"query"},{"schema":{"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdBefore","in":"query"},{"schema":{"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdFrom","in":"query"},{"schema":{"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdTo","in":"query"},{"schema":{"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedOn","in":"query"},{"schema":{"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedAfter","in":"query"},{"schema":{"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedBefore","in":"query"},{"schema":{"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedFrom","in":"query"},{"schema":{"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedTo","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, name, contactType, role, status, email. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, name, contactType, role, status, email. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["person","company"],"description":"Filter by contact type: person (individual) or company (business)."},"required":false,"description":"Filter by contact type: person (individual) or company (business).","name":"type","in":"query"},{"schema":{"type":"string","enum":["client","provider","lead","debtor","creditor","student","teacher","unspecified"],"description":"Filter by contact role: client, provider, lead, debtor, creditor, student, teacher or unspecified."},"required":false,"description":"Filter by contact role: client, provider, lead, debtor, creditor, student, teacher or unspecified.","name":"role","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Filter by email: matches against the email addresses of the contact."},"required":false,"description":"Filter by email: matches against the email addresses of the contact.","name":"email","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Filter by phone: matches against the phone numbers of the contact."},"required":false,"description":"Filter by phone: matches against the phone numbers of the contact.","name":"phone","in":"query"},{"schema":{"type":"boolean","description":"Filter by whether the contact has access to the app: \"true\" returns only app users, \"false\" only those who are not. Omit it to skip the filter."},"required":false,"description":"Filter by whether the contact has access to the app: \"true\" returns only app users, \"false\" only those who are not. Omit it to skip the filter.","name":"isAppUser","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactList"},"example":{"data":[{"id":"contact_9f3a2b","name":"Example contact","contactType":"person","role":"client","status":"active","nif":"B00000000","commercialName":"Example commercial name","position":"Example position","contactNumber":"2026-0001","emails":[{"id":"email_9f3a2b","label":"Main","email":"ana.garcia@example.com","isPrimary":true}],"billingEmail":"ana.garcia@example.com","phoneNumbers":[{"id":"phone_number_9f3a2b","label":"Main","number":"+34 600 000 000","countryCode":"+34","isPrimary":true}],"websites":[{"id":"website_9f3a2b","label":"Main","url":"https://example.com/resource"}],"addresses":[{"id":"address_9f3a2b","label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES","isMain":true}],"folder":"Example folder","discountPercentage":1,"preferredLanguage":"es-ES","currency":"EUR","paymentMethod":{"type":"bank_transfer","customValue":"Example custom value"},"paymentDays":[1],"expirationDays":1,"subscribedToMarketing":true,"isAppUser":true,"customFields":{"example":"example"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/contacts/list-contacts"}},"post":{"operationId":"createContact","tags":["Contacts"],"summary":"Create a contact","description":"Creates a contact with domain validation (email, NIF, field allow-list). Returns the created contact in detail.\n\n**Required scope:** `contacts:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"contacts:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactCreateBody"},"example":{"name":"Producciones Delta S.L.","contactType":"company","role":"client","nif":"B00000000","email":"hola@example.com","phone":"+34 600 000 000","addressLine1":"Calle de la Cámara 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES","preferredLanguage":"es-ES","currency":"EUR"}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactDetailResponse"},"example":{"data":{"id":"contact_9f3a2b","name":"Example contact","contactType":"person","role":"client","status":"active","nif":"B00000000","commercialName":"Example commercial name","position":"Example position","contactNumber":"2026-0001","emails":[{"id":"email_9f3a2b","label":"Main","email":"ana.garcia@example.com","isPrimary":true}],"billingEmail":"ana.garcia@example.com","phoneNumbers":[{"id":"phone_number_9f3a2b","label":"Main","number":"+34 600 000 000","countryCode":"+34","isPrimary":true}],"websites":[{"id":"website_9f3a2b","label":"Main","url":"https://example.com/resource"}],"addresses":[{"id":"address_9f3a2b","label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES","isMain":true}],"folder":"Example folder","discountPercentage":1,"preferredLanguage":"es-ES","currency":"EUR","paymentMethod":{"type":"bank_transfer","customValue":"Example custom value"},"paymentDays":[1],"expirationDays":1,"subscribedToMarketing":true,"isAppUser":true,"customFields":{"example":"example"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","relatedContacts":[{"id":"related_contact_9f3a2b","name":"Example related contact","commercialName":"Example commercial name","contactType":"person","role":"client","status":"active","relationRole":"Example relation role"}]}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/contacts/create-a-contact"}}},"/api/v1/contacts/{contactId}":{"get":{"operationId":"getContact","tags":["Contacts"],"summary":"Get a contact","description":"Returns the detail of a contact by its identifier.\n\n**Required scope:** `contacts:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"contacts:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Contact identifier."},"required":true,"description":"Contact identifier.","name":"contactId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactDetailResponse"},"example":{"data":{"id":"contact_9f3a2b","name":"Example contact","contactType":"person","role":"client","status":"active","nif":"B00000000","commercialName":"Example commercial name","position":"Example position","contactNumber":"2026-0001","emails":[{"id":"email_9f3a2b","label":"Main","email":"ana.garcia@example.com","isPrimary":true}],"billingEmail":"ana.garcia@example.com","phoneNumbers":[{"id":"phone_number_9f3a2b","label":"Main","number":"+34 600 000 000","countryCode":"+34","isPrimary":true}],"websites":[{"id":"website_9f3a2b","label":"Main","url":"https://example.com/resource"}],"addresses":[{"id":"address_9f3a2b","label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES","isMain":true}],"folder":"Example folder","discountPercentage":1,"preferredLanguage":"es-ES","currency":"EUR","paymentMethod":{"type":"bank_transfer","customValue":"Example custom value"},"paymentDays":[1],"expirationDays":1,"subscribedToMarketing":true,"isAppUser":true,"customFields":{"example":"example"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","relatedContacts":[{"id":"related_contact_9f3a2b","name":"Example related contact","commercialName":"Example commercial name","contactType":"person","role":"client","status":"active","relationRole":"Example relation role"}]}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/contacts/get-a-contact"}},"delete":{"operationId":"deleteContact","tags":["Contacts"],"summary":"Delete a contact","description":"Deletes the contact and everything hanging from it: its relationships with other contacts (in both directions), its notes, its files, its tasks, its payment methods and its customer portal access. The related contacts themselves are NOT deleted. It is NOT reversible. Responds 204 with no body: the contact no longer exists for the API (its GET responds 404). 409 `contact_in_use` if anything still uses the contact — orders, projects (also as their contact person), quotes, invoices, proformas, credit notes, sales receipts, supplier invoices, contracts, subrents (as provider), purchase orders (as supplier), SEPA mandates, receipts or consignments —: nothing is deleted and `errors[]` carries one entry per type that uses it (`path` is the type, `count` how many). Archive it instead with `PATCH /api/v1/contacts/{contactId}` and `status: archived`. 404 if the contact does not exist or belongs to another account.\n\n**Required scope:** `contacts:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"contacts:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Contact identifier."},"required":true,"description":"Contact identifier.","name":"contactId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"responses":{"204":{"description":"No content.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"},"contact_in_use":{"$ref":"#/components/examples/Problem_contact_in_use"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/contacts/delete-a-contact"}},"patch":{"operationId":"updateContact","tags":["Contacts"],"summary":"Update a contact","description":"Partially updates a contact (send only the fields to change). The arrays of emails, phones and addresses replace the existing list entirely. Returns the updated contact in detail.\n\n**Required scope:** `contacts:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"contacts:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Contact identifier."},"required":true,"description":"Contact identifier.","name":"contactId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactUpdateBody"},"example":{"role":"client","status":"active","emails":[{"email":"facturacion@example.com","label":"Facturación"},{"email":"produccion@example.com","label":"Producción"}],"discountPercentage":10}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactDetailResponse"},"example":{"data":{"id":"contact_9f3a2b","name":"Example contact","contactType":"person","role":"client","status":"active","nif":"B00000000","commercialName":"Example commercial name","position":"Example position","contactNumber":"2026-0001","emails":[{"id":"email_9f3a2b","label":"Main","email":"ana.garcia@example.com","isPrimary":true}],"billingEmail":"ana.garcia@example.com","phoneNumbers":[{"id":"phone_number_9f3a2b","label":"Main","number":"+34 600 000 000","countryCode":"+34","isPrimary":true}],"websites":[{"id":"website_9f3a2b","label":"Main","url":"https://example.com/resource"}],"addresses":[{"id":"address_9f3a2b","label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES","isMain":true}],"folder":"Example folder","discountPercentage":1,"preferredLanguage":"es-ES","currency":"EUR","paymentMethod":{"type":"bank_transfer","customValue":"Example custom value"},"paymentDays":[1],"expirationDays":1,"subscribedToMarketing":true,"isAppUser":true,"customFields":{"example":"example"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","relatedContacts":[{"id":"related_contact_9f3a2b","name":"Example related contact","commercialName":"Example commercial name","contactType":"person","role":"client","status":"active","relationRole":"Example relation role"}]}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"},"address_in_use":{"$ref":"#/components/examples/Problem_address_in_use"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/contacts/update-a-contact"}}},"/api/v1/contacts/{contactId}/preferences":{"patch":{"operationId":"updateContactPreferences","tags":["Contacts"],"summary":"Update the commercial terms of a contact","description":"Sets how and when this contact pays: currency, language of its documents, billing email, payment method, payment days, due date, usual discount and the electronic invoicing codes for public administration. The default tax configuration is NOT part of the public contract. Returns the updated contact in detail.\n\n**Required scope:** `contacts:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"contacts:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Contact identifier."},"required":true,"description":"Contact identifier.","name":"contactId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactPreferencesBody"},"example":{"currency":"EUR","preferredLanguage":"es-ES","billingEmail":"facturacion@example.com","paymentMethod":{"type":"bank_transfer"},"paymentDays":[5,20],"expirationDays":30,"discountSettings":{"percentage":10}}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactDetailResponse"},"example":{"data":{"id":"contact_9f3a2b","name":"Example contact","contactType":"person","role":"client","status":"active","nif":"B00000000","commercialName":"Example commercial name","position":"Example position","contactNumber":"2026-0001","emails":[{"id":"email_9f3a2b","label":"Main","email":"ana.garcia@example.com","isPrimary":true}],"billingEmail":"ana.garcia@example.com","phoneNumbers":[{"id":"phone_number_9f3a2b","label":"Main","number":"+34 600 000 000","countryCode":"+34","isPrimary":true}],"websites":[{"id":"website_9f3a2b","label":"Main","url":"https://example.com/resource"}],"addresses":[{"id":"address_9f3a2b","label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES","isMain":true}],"folder":"Example folder","discountPercentage":1,"preferredLanguage":"es-ES","currency":"EUR","paymentMethod":{"type":"bank_transfer","customValue":"Example custom value"},"paymentDays":[1],"expirationDays":1,"subscribedToMarketing":true,"isAppUser":true,"customFields":{"example":"example"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","relatedContacts":[{"id":"related_contact_9f3a2b","name":"Example related contact","commercialName":"Example commercial name","contactType":"person","role":"client","status":"active","relationRole":"Example relation role"}]}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/contacts/update-the-commercial-terms-of-a-contact"}}},"/api/v1/contacts/{contactId}/addresses":{"post":{"operationId":"addContactAddress","tags":["Contacts"],"summary":"Add an address to a contact","description":"A contact with several addresses (billing, shipping, shooting) is the normal case, and contact creation only accepts the first one. With `isMain: true` this one becomes the main address and the previous one is demoted. Returns the full contact, the same projection as its GET.\n\n**Required scope:** `contacts:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"contacts:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Contact identifier."},"required":true,"description":"Contact identifier.","name":"contactId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactAddressCreateBody"},"example":{"label":"Almacén","addressLine1":"Polígono Las Mercedes, nave 12","city":"Madrid","province":"Madrid","postcode":"28022","country":"ES","isMain":false}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactDetailResponse"},"example":{"data":{"id":"contact_9f3a2b","name":"Example contact","contactType":"person","role":"client","status":"active","nif":"B00000000","commercialName":"Example commercial name","position":"Example position","contactNumber":"2026-0001","emails":[{"id":"email_9f3a2b","label":"Main","email":"ana.garcia@example.com","isPrimary":true}],"billingEmail":"ana.garcia@example.com","phoneNumbers":[{"id":"phone_number_9f3a2b","label":"Main","number":"+34 600 000 000","countryCode":"+34","isPrimary":true}],"websites":[{"id":"website_9f3a2b","label":"Main","url":"https://example.com/resource"}],"addresses":[{"id":"address_9f3a2b","label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES","isMain":true}],"folder":"Example folder","discountPercentage":1,"preferredLanguage":"es-ES","currency":"EUR","paymentMethod":{"type":"bank_transfer","customValue":"Example custom value"},"paymentDays":[1],"expirationDays":1,"subscribedToMarketing":true,"isAppUser":true,"customFields":{"example":"example"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","relatedContacts":[{"id":"related_contact_9f3a2b","name":"Example related contact","commercialName":"Example commercial name","contactType":"person","role":"client","status":"active","relationRole":"Example relation role"}]}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/contacts/add-an-address-to-a-contact"}}},"/api/v1/contacts/{contactId}/addresses/{addressId}":{"patch":{"operationId":"updateContactAddress","tags":["Contacts"],"summary":"Update an address of a contact","description":"Corrects an address or promotes it to main (send only the fields to change; an empty body responds 400). 404 if the contact or the address does not exist. Returns the full contact, the same projection as its GET.\n\n**Required scope:** `contacts:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"contacts:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Contact identifier."},"required":true,"description":"Contact identifier.","name":"contactId","in":"path"},{"schema":{"type":"string","minLength":1,"description":"Address identifier."},"required":true,"description":"Address identifier.","name":"addressId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactAddressUpdateBody"},"example":{"label":"Almacén","addressLine1":"Polígono Las Mercedes, nave 12","city":"Madrid","province":"Madrid","postcode":"28022","country":"ES","isMain":false}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactDetailResponse"},"example":{"data":{"id":"contact_9f3a2b","name":"Example contact","contactType":"person","role":"client","status":"active","nif":"B00000000","commercialName":"Example commercial name","position":"Example position","contactNumber":"2026-0001","emails":[{"id":"email_9f3a2b","label":"Main","email":"ana.garcia@example.com","isPrimary":true}],"billingEmail":"ana.garcia@example.com","phoneNumbers":[{"id":"phone_number_9f3a2b","label":"Main","number":"+34 600 000 000","countryCode":"+34","isPrimary":true}],"websites":[{"id":"website_9f3a2b","label":"Main","url":"https://example.com/resource"}],"addresses":[{"id":"address_9f3a2b","label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES","isMain":true}],"folder":"Example folder","discountPercentage":1,"preferredLanguage":"es-ES","currency":"EUR","paymentMethod":{"type":"bank_transfer","customValue":"Example custom value"},"paymentDays":[1],"expirationDays":1,"subscribedToMarketing":true,"isAppUser":true,"customFields":{"example":"example"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","relatedContacts":[{"id":"related_contact_9f3a2b","name":"Example related contact","commercialName":"Example commercial name","contactType":"person","role":"client","status":"active","relationRole":"Example relation role"}]}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/contacts/update-an-address-of-a-contact"}},"delete":{"operationId":"deleteContactAddress","tags":["Contacts"],"summary":"Remove an address from a contact","description":"Removes one address from the contact. If it was the main address, the first remaining one becomes main. It does NOT delete the contact and it is NOT reversible. 409 `address_in_use` if an order uses it as its billing or shipping address: nothing is removed and `errors[0].count` says how many orders; change the address on them first. 404 if the contact or the address does not exist. Returns the full contact, the same projection as its GET, so the remaining `addresses` come back with it.\n\n**Required scope:** `contacts:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"contacts:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Contact identifier."},"required":true,"description":"Contact identifier.","name":"contactId","in":"path"},{"schema":{"type":"string","minLength":1,"description":"Address identifier."},"required":true,"description":"Address identifier.","name":"addressId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactDetailResponse"},"example":{"data":{"id":"contact_9f3a2b","name":"Example contact","contactType":"person","role":"client","status":"active","nif":"B00000000","commercialName":"Example commercial name","position":"Example position","contactNumber":"2026-0001","emails":[{"id":"email_9f3a2b","label":"Main","email":"ana.garcia@example.com","isPrimary":true}],"billingEmail":"ana.garcia@example.com","phoneNumbers":[{"id":"phone_number_9f3a2b","label":"Main","number":"+34 600 000 000","countryCode":"+34","isPrimary":true}],"websites":[{"id":"website_9f3a2b","label":"Main","url":"https://example.com/resource"}],"addresses":[{"id":"address_9f3a2b","label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES","isMain":true}],"folder":"Example folder","discountPercentage":1,"preferredLanguage":"es-ES","currency":"EUR","paymentMethod":{"type":"bank_transfer","customValue":"Example custom value"},"paymentDays":[1],"expirationDays":1,"subscribedToMarketing":true,"isAppUser":true,"customFields":{"example":"example"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","relatedContacts":[{"id":"related_contact_9f3a2b","name":"Example related contact","commercialName":"Example commercial name","contactType":"person","role":"client","status":"active","relationRole":"Example relation role"}]}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"},"address_in_use":{"$ref":"#/components/examples/Problem_address_in_use"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/contacts/remove-an-address-from-a-contact"}}},"/api/v1/contacts/{contactId}/related-contacts":{"get":{"operationId":"listRelatedContacts","tags":["Contacts"],"summary":"List the contacts related to a contact","description":"Returns the contacts tied to this one, in both directions of the relationship, each with the role of the relationship. The contact detail returns the same list under `relatedContacts`; this is the sub-resource for reading it on its own.\n\n**Required scope:** `contacts:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"contacts:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Contact identifier."},"required":true,"description":"Contact identifier.","name":"contactId","in":"path"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RelatedContactItems"},"example":{"data":[{"id":"related_contact_9f3a2b","name":"Example related contact","commercialName":"Example commercial name","contactType":"person","role":"client","status":"active","relationRole":"Example relation role"}]}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/contacts/list-the-contacts-related-to-a-contact"}},"post":{"operationId":"addRelatedContact","tags":["Contacts"],"summary":"Relate two contacts","description":"Ties a contact to another with a role (the contact person of a company, the director of a production). A company relating a person must give the role (400 otherwise); a person relating a company must not (the role lives on the inverse relationship); any other pair is free and the role is recorded. 409 if the pair was already related. Returns the relationship as recorded. Returns the full contact, with `relatedContacts` as they now stand, the same projection as its GET.\n\n**Required scope:** `contacts:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"contacts:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Identifier of the main contact."},"required":true,"description":"Identifier of the main contact.","name":"contactId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RelatedContactCreateBody"},"example":{"relatedContactId":"cont_3d9b77","relationRole":"Persona de contacto en rodaje"}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactDetailResponse"},"example":{"data":{"id":"contact_9f3a2b","name":"Example contact","contactType":"person","role":"client","status":"active","nif":"B00000000","commercialName":"Example commercial name","position":"Example position","contactNumber":"2026-0001","emails":[{"id":"email_9f3a2b","label":"Main","email":"ana.garcia@example.com","isPrimary":true}],"billingEmail":"ana.garcia@example.com","phoneNumbers":[{"id":"phone_number_9f3a2b","label":"Main","number":"+34 600 000 000","countryCode":"+34","isPrimary":true}],"websites":[{"id":"website_9f3a2b","label":"Main","url":"https://example.com/resource"}],"addresses":[{"id":"address_9f3a2b","label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES","isMain":true}],"folder":"Example folder","discountPercentage":1,"preferredLanguage":"es-ES","currency":"EUR","paymentMethod":{"type":"bank_transfer","customValue":"Example custom value"},"paymentDays":[1],"expirationDays":1,"subscribedToMarketing":true,"isAppUser":true,"customFields":{"example":"example"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","relatedContacts":[{"id":"related_contact_9f3a2b","name":"Example related contact","commercialName":"Example commercial name","contactType":"person","role":"client","status":"active","relationRole":"Example relation role"}]}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/contacts/relate-two-contacts"}}},"/api/v1/contacts/{contactId}/related-contacts/{relatedContactId}":{"patch":{"operationId":"updateRelatedContact","tags":["Contacts"],"summary":"Change the role of a relationship","description":"Updates the role with which two contacts are related. The pair must be given in the order it was created. `relationRole` is required (an empty string clears it); 404 if the contacts are not related. Returns the relationship as it now stands. Returns the full contact, with `relatedContacts` as they now stand, the same projection as its GET.\n\n**Required scope:** `contacts:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"contacts:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Identifier of the main contact."},"required":true,"description":"Identifier of the main contact.","name":"contactId","in":"path"},{"schema":{"type":"string","minLength":1,"description":"Identifier of the related contact."},"required":true,"description":"Identifier of the related contact.","name":"relatedContactId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RelatedContactUpdateBody"},"example":{"relationRole":"Directora de producción"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactDetailResponse"},"example":{"data":{"id":"contact_9f3a2b","name":"Example contact","contactType":"person","role":"client","status":"active","nif":"B00000000","commercialName":"Example commercial name","position":"Example position","contactNumber":"2026-0001","emails":[{"id":"email_9f3a2b","label":"Main","email":"ana.garcia@example.com","isPrimary":true}],"billingEmail":"ana.garcia@example.com","phoneNumbers":[{"id":"phone_number_9f3a2b","label":"Main","number":"+34 600 000 000","countryCode":"+34","isPrimary":true}],"websites":[{"id":"website_9f3a2b","label":"Main","url":"https://example.com/resource"}],"addresses":[{"id":"address_9f3a2b","label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES","isMain":true}],"folder":"Example folder","discountPercentage":1,"preferredLanguage":"es-ES","currency":"EUR","paymentMethod":{"type":"bank_transfer","customValue":"Example custom value"},"paymentDays":[1],"expirationDays":1,"subscribedToMarketing":true,"isAppUser":true,"customFields":{"example":"example"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","relatedContacts":[{"id":"related_contact_9f3a2b","name":"Example related contact","commercialName":"Example commercial name","contactType":"person","role":"client","status":"active","relationRole":"Example relation role"}]}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/contacts/change-the-role-of-a-relationship"}},"delete":{"operationId":"removeRelatedContact","tags":["Contacts"],"summary":"Unrelate two contacts","description":"Removes the relationship between two contacts, in both directions, whichever order the pair is given in. It does NOT delete either contact. 404 if they were not related. Returns the main contact in detail, the same projection as its GET, so the remaining `relatedContacts` come back with it.\n\n**Required scope:** `contacts:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"contacts:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Identifier of the main contact."},"required":true,"description":"Identifier of the main contact.","name":"contactId","in":"path"},{"schema":{"type":"string","minLength":1,"description":"Identifier of the related contact."},"required":true,"description":"Identifier of the related contact.","name":"relatedContactId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactDetailResponse"},"example":{"data":{"id":"contact_9f3a2b","name":"Example contact","contactType":"person","role":"client","status":"active","nif":"B00000000","commercialName":"Example commercial name","position":"Example position","contactNumber":"2026-0001","emails":[{"id":"email_9f3a2b","label":"Main","email":"ana.garcia@example.com","isPrimary":true}],"billingEmail":"ana.garcia@example.com","phoneNumbers":[{"id":"phone_number_9f3a2b","label":"Main","number":"+34 600 000 000","countryCode":"+34","isPrimary":true}],"websites":[{"id":"website_9f3a2b","label":"Main","url":"https://example.com/resource"}],"addresses":[{"id":"address_9f3a2b","label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES","isMain":true}],"folder":"Example folder","discountPercentage":1,"preferredLanguage":"es-ES","currency":"EUR","paymentMethod":{"type":"bank_transfer","customValue":"Example custom value"},"paymentDays":[1],"expirationDays":1,"subscribedToMarketing":true,"isAppUser":true,"customFields":{"example":"example"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","relatedContacts":[{"id":"related_contact_9f3a2b","name":"Example related contact","commercialName":"Example commercial name","contactType":"person","role":"client","status":"active","relationRole":"Example relation role"}]}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/contacts/unrelate-two-contacts"}}},"/api/v1/items":{"get":{"operationId":"listItems","tags":["Items"],"summary":"List items","description":"Returns the inventory item catalog, cursor-paginated. Strict per-subscription tenancy.\n\n**Required scope:** `items:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"items:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdOn","in":"query"},{"schema":{"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdAfter","in":"query"},{"schema":{"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdBefore","in":"query"},{"schema":{"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdFrom","in":"query"},{"schema":{"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdTo","in":"query"},{"schema":{"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedOn","in":"query"},{"schema":{"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedAfter","in":"query"},{"schema":{"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedBefore","in":"query"},{"schema":{"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedFrom","in":"query"},{"schema":{"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedTo","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, name, sku, salePrice, depositValue, serializedItemsCount, collectionName. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, name, sku, salePrice, depositValue, serializedItemsCount, collectionName. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Free-text search (currently ILIKE over name, SKU, synonyms and serialized item codes). Semantics are NOT contractual: they may evolve without notice."},"required":false,"description":"Free-text search (currently ILIKE over name, SKU, synonyms and serialized item codes). Semantics are NOT contractual: they may evolve without notice.","name":"query","in":"query"},{"schema":{"type":"string","enum":["serialized","bulk"],"description":"Filter by stock calculation method: serialized (by serialized items) or bulk (in bulk)."},"required":false,"description":"Filter by stock calculation method: serialized (by serialized items) or bulk (in bulk).","name":"stockType","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["serialized","bulk"]},"minItems":1,"maxItems":50,"description":"Filter by stockType, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by stockType, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"stockTypes","in":"query"},{"schema":{"type":"string","maxLength":100,"description":"Filter by identifier of the collection the item belongs to."},"required":false,"description":"Filter by identifier of the collection the item belongs to.","name":"collectionId","in":"query"},{"schema":{"type":"array","items":{"type":"string","maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by collectionId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by collectionId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"collectionIds","in":"query"},{"schema":{"type":"string","maxLength":4000,"description":"Batch lookup by comma-separated identifiers (between 1 and 100), intended for synchronization."},"required":false,"description":"Batch lookup by comma-separated identifiers (between 1 and 100), intended for synchronization.","name":"ids","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemList"},"example":{"data":[{"id":"item_9f3a2b","name":"Example item","sku":"CAM-FX6-01","description":"Example text.","orderInfo":"Example order info","ean":"0000000000000","itemType":"fixed","stockCalculationMethod":"bulk","collectionId":"collection_9f3a2b","collectionName":"Example collection name","images":["Example images"],"salePrice":"120.00","depositValue":"120.00","minStock":1,"serializedItemsCount":1,"pricingSettings":{"type":"periodPrice","price":"120.00","period":"hour"},"insuranceEnabled":true,"discountEnabled":true,"bufferBefore":1,"bufferBeforeUnit":"hour","bufferAfter":1,"bufferAfterUnit":"hour","physicalProperties":{"weight":1,"width":1,"height":1,"length":1,"volume":1,"current":1,"power":1},"variants":[{"variantId":"variant_9f3a2b","variantName":"Example variant name","variantPrice":"120.00","salePrice":"120.00","ean":"0000000000000"}],"tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"customFields":{"example":"example"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/items/list-items"}},"post":{"operationId":"createItem","tags":["Items"],"summary":"Create an item","description":"Registers an item in the inventory catalog. The SKU is optional: if omitted, the server assigns the next available one in the account. With inventoryMethod=serialized each physical unit is tracked by its serial number; with bulk it is tracked by quantity, and it cannot be changed once there is stock. Returns the created item in detail.\n\n**Required scope:** `items:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"items:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemCreateBody"},"example":{"name":"Sony FX6","sku":"CAM-FX6-01","inventoryMethod":"serialized","tags":["Cámaras","Cine"],"showInOrderSearch":true}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemDetailResponse"},"example":{"data":{"id":"item_9f3a2b","name":"Example item","sku":"CAM-FX6-01","description":"Example text.","orderInfo":"Example order info","ean":"0000000000000","itemType":"fixed","stockCalculationMethod":"bulk","collectionId":"collection_9f3a2b","collectionName":"Example collection name","images":["Example images"],"salePrice":"120.00","depositValue":"120.00","minStock":1,"serializedItemsCount":1,"pricingSettings":{"type":"periodPrice","price":"120.00","period":"hour"},"insuranceEnabled":true,"discountEnabled":true,"bufferBefore":1,"bufferBeforeUnit":"hour","bufferAfter":1,"bufferAfterUnit":"hour","physicalProperties":{"weight":1,"width":1,"height":1,"length":1,"volume":1,"current":1,"power":1},"variants":[{"variantId":"variant_9f3a2b","variantName":"Example variant name","variantPrice":"120.00","salePrice":"120.00","ean":"0000000000000"}],"tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"customFields":{"example":"example"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","replacementValue":"120.00","accessoryIds":["accessory_9f3a2b"],"alternativeIds":["alternative_9f3a2b"]}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/items/create-an-item"}}},"/api/v1/items/{itemId}":{"get":{"operationId":"getItem","tags":["Items"],"summary":"Get an item","description":"Returns the detail of an item, including replacement value, accessories and alternatives.\n\n**Required scope:** `items:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"items:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Item identifier."},"required":true,"description":"Item identifier.","name":"itemId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemDetailResponse"},"example":{"data":{"id":"item_9f3a2b","name":"Example item","sku":"CAM-FX6-01","description":"Example text.","orderInfo":"Example order info","ean":"0000000000000","itemType":"fixed","stockCalculationMethod":"bulk","collectionId":"collection_9f3a2b","collectionName":"Example collection name","images":["Example images"],"salePrice":"120.00","depositValue":"120.00","minStock":1,"serializedItemsCount":1,"pricingSettings":{"type":"periodPrice","price":"120.00","period":"hour"},"insuranceEnabled":true,"discountEnabled":true,"bufferBefore":1,"bufferBeforeUnit":"hour","bufferAfter":1,"bufferAfterUnit":"hour","physicalProperties":{"weight":1,"width":1,"height":1,"length":1,"volume":1,"current":1,"power":1},"variants":[{"variantId":"variant_9f3a2b","variantName":"Example variant name","variantPrice":"120.00","salePrice":"120.00","ean":"0000000000000"}],"tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"customFields":{"example":"example"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","replacementValue":"120.00","accessoryIds":["accessory_9f3a2b"],"alternativeIds":["alternative_9f3a2b"]}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/items/get-an-item"}},"delete":{"operationId":"deleteItem","tags":["Items"],"summary":"Delete an item","description":"Deletes the item from the catalog and everything hanging from it: its serialized units, its notes, its files and its tasks; it is also removed from the alternatives of other items and from order import templates. It is NOT reversible. 409 when the item cannot be deleted: it has units reserved or not yet returned in orders, it is included in a kit, it has active subrents, or it is an accessory or sub-item of another item — `detail` says which. Responds 204 with no body: the item no longer exists for the API (its GET responds 404).\n\n**Required scope:** `items:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"items:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Item identifier."},"required":true,"description":"Item identifier.","name":"itemId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"responses":{"204":{"description":"No content.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/items/delete-an-item"}},"patch":{"operationId":"updateItem","tags":["Items"],"summary":"Update an item","description":"Updates the catalog metadata of an item (send only the fields to change). `synonyms` and `tags` replace the whole list. The stock method and the item type can NOT be changed here: they are destructive once there is stock or variants, and are set on create. Returns the updated item in detail.\n\n**Required scope:** `items:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"items:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Item identifier."},"required":true,"description":"Item identifier.","name":"itemId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemUpdateBody"},"example":{"name":"Sony FX6 (cuerpo)","description":"Cámara de cine digital full-frame, montura E.","synonyms":["FX6","Sony cine full frame"],"tags":["Cámaras","Cine"]}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemDetailResponse"},"example":{"data":{"id":"item_9f3a2b","name":"Example item","sku":"CAM-FX6-01","description":"Example text.","orderInfo":"Example order info","ean":"0000000000000","itemType":"fixed","stockCalculationMethod":"bulk","collectionId":"collection_9f3a2b","collectionName":"Example collection name","images":["Example images"],"salePrice":"120.00","depositValue":"120.00","minStock":1,"serializedItemsCount":1,"pricingSettings":{"type":"periodPrice","price":"120.00","period":"hour"},"insuranceEnabled":true,"discountEnabled":true,"bufferBefore":1,"bufferBeforeUnit":"hour","bufferAfter":1,"bufferAfterUnit":"hour","physicalProperties":{"weight":1,"width":1,"height":1,"length":1,"volume":1,"current":1,"power":1},"variants":[{"variantId":"variant_9f3a2b","variantName":"Example variant name","variantPrice":"120.00","salePrice":"120.00","ean":"0000000000000"}],"tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"customFields":{"example":"example"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","replacementValue":"120.00","accessoryIds":["accessory_9f3a2b"],"alternativeIds":["alternative_9f3a2b"]}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/items/update-an-item"}}},"/api/v1/items/{itemId}/physical-properties":{"patch":{"operationId":"updateItemPhysicalProperties","tags":["Items"],"summary":"Update weight and dimensions","description":"Sets the weight, dimensions, volume and power consumption of an item. An omitted field is left as is; a 0 means \"unspecified\". It is the data that load plans and freight depend on. Returns the updated item in detail.\n\n**Required scope:** `items:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"items:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Item identifier."},"required":true,"description":"Item identifier.","name":"itemId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemPhysicalPropertiesBody"},"example":{"weight":1.4,"length":24,"width":12,"height":14,"volume":4,"current":2.1,"power":25}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemDetailResponse"},"example":{"data":{"id":"item_9f3a2b","name":"Example item","sku":"CAM-FX6-01","description":"Example text.","orderInfo":"Example order info","ean":"0000000000000","itemType":"fixed","stockCalculationMethod":"bulk","collectionId":"collection_9f3a2b","collectionName":"Example collection name","images":["Example images"],"salePrice":"120.00","depositValue":"120.00","minStock":1,"serializedItemsCount":1,"pricingSettings":{"type":"periodPrice","price":"120.00","period":"hour"},"insuranceEnabled":true,"discountEnabled":true,"bufferBefore":1,"bufferBeforeUnit":"hour","bufferAfter":1,"bufferAfterUnit":"hour","physicalProperties":{"weight":1,"width":1,"height":1,"length":1,"volume":1,"current":1,"power":1},"variants":[{"variantId":"variant_9f3a2b","variantName":"Example variant name","variantPrice":"120.00","salePrice":"120.00","ean":"0000000000000"}],"tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"customFields":{"example":"example"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","replacementValue":"120.00","accessoryIds":["accessory_9f3a2b"],"alternativeIds":["alternative_9f3a2b"]}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/items/update-weight-and-dimensions"}}},"/api/v1/items/{itemId}/pricing":{"patch":{"operationId":"updateItemPricing","tags":["Items"],"summary":"Update the pricing of an item","description":"Sets the rental price, the sale price, the deposit, the replacement value and the time margins that block the item around a rental. The internal and external cost are NOT part of the public contract and cannot be written here. Returns the updated item in detail.\n\n**Required scope:** `items:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"items:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Item identifier."},"required":true,"description":"Item identifier.","name":"itemId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemPricingBody"},"example":{"pricingSettings":{"type":"periodPrice","price":"180.00","period":"day"},"salePrice":"5900.00","depositValue":"1000.00","replacementValue":"6500.00","insuranceEnabled":true,"discountEnabled":true,"bufferBefore":1,"bufferBeforeUnit":"day","bufferAfter":1,"bufferAfterUnit":"day"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemDetailResponse"},"example":{"data":{"id":"item_9f3a2b","name":"Example item","sku":"CAM-FX6-01","description":"Example text.","orderInfo":"Example order info","ean":"0000000000000","itemType":"fixed","stockCalculationMethod":"bulk","collectionId":"collection_9f3a2b","collectionName":"Example collection name","images":["Example images"],"salePrice":"120.00","depositValue":"120.00","minStock":1,"serializedItemsCount":1,"pricingSettings":{"type":"periodPrice","price":"120.00","period":"hour"},"insuranceEnabled":true,"discountEnabled":true,"bufferBefore":1,"bufferBeforeUnit":"hour","bufferAfter":1,"bufferAfterUnit":"hour","physicalProperties":{"weight":1,"width":1,"height":1,"length":1,"volume":1,"current":1,"power":1},"variants":[{"variantId":"variant_9f3a2b","variantName":"Example variant name","variantPrice":"120.00","salePrice":"120.00","ean":"0000000000000"}],"tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"customFields":{"example":"example"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","replacementValue":"120.00","accessoryIds":["accessory_9f3a2b"],"alternativeIds":["alternative_9f3a2b"]}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/items/update-the-pricing-of-an-item"}}},"/api/v1/availability/check":{"post":{"operationId":"checkAvailability","tags":["Availability"],"summary":"Check item availability","description":"Checks the availability of a batch of items (1-100) over a common date range, each with the quantity you intend to book (1 by default). Idempotent query (POST because of the structured body). Shares the availability quota of 30 req/min. One entry per requested item, in request order: its availability (`available`, `shortfall`, `conflictingPeriods` for that quantity, and `commitments`: the orders that hold units of it in the window, with their number, peak quantity and dates) or a per-item `error` when the item does not exist in the account.\n\n**Required scope:** `availability:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"availability:read","x-rateLimit":{"global":{"perMinute":120},"availability":{"perMinute":30}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvailabilityCheckBody"},"example":{"items":[{"itemId":"itm_9f3a2b","variantId":"var_rojo","transactionType":"rental","quantity":4},{"itemId":"itm_camara_a7"}],"startDate":"2026-09-01T08:00:00+02:00","endDate":"2026-09-05T20:00:00+02:00"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvailabilityCheckEntryItems"},"example":{"data":[{"itemId":"item_9f3a2b","variantId":"variant_9f3a2b","itemName":"Example item name","quantity":1,"available":true,"status":"ok","totalStock":1,"reserved":1,"minRemaining":1,"shortfall":1,"temporaryAvailable":1,"conflictingPeriods":["Example conflicting periods"],"commitments":[{"orderId":"order_9f3a2b","orderNumber":"2026-0001","quantity":1,"startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z"}],"checkedAt":"2026-09-01T08:00:00.000Z"}]}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/availability/check-item-availability"}}},"/api/v1/orders":{"get":{"operationId":"listOrders","tags":["Orders"],"summary":"List orders","description":"Returns the rental orders, cursor-paginated. The `status` filter uses high-level operational buckets. The list is strict to the subscription of the key.\n\n**Required scope:** `orders:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"orders:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdOn","in":"query"},{"schema":{"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdAfter","in":"query"},{"schema":{"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdBefore","in":"query"},{"schema":{"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdFrom","in":"query"},{"schema":{"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdTo","in":"query"},{"schema":{"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedOn","in":"query"},{"schema":{"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedAfter","in":"query"},{"schema":{"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedBefore","in":"query"},{"schema":{"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedFrom","in":"query"},{"schema":{"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedTo","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":200,"description":"Free-text search on the order number, the project name or alias and the external reference."},"required":false,"description":"Free-text search on the order number, the project name or alias and the external reference.","name":"q","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, startDate, endDate, orderNumber, grossPrice, rentalDays, itemsCount. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, startDate, endDate, orderNumber, grossPrice, rentalDays, itemsCount. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["draft","reserved","prepared","in_use","returned","completed","cancelled"],"description":"Filter by operational status bucket (UI view): draft, reserved, prepared (includes partial preparation), in_use (picked up/in use), returned (includes partial return/check-in), completed (checked in and completed) or cancelled."},"required":false,"description":"Filter by operational status bucket (UI view): draft, reserved, prepared (includes partial preparation), in_use (picked up/in use), returned (includes partial return/check-in), completed (checked in and completed) or cancelled.","name":"status","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["draft","reserved","prepared","in_use","returned","completed","cancelled"]},"minItems":1,"maxItems":50,"description":"Filter by status, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by status, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"statuses","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by order contact identifier."},"required":false,"description":"Filter by order contact identifier.","name":"contactId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by contactId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by contactId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"contactIds","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by identifier of the project the order belongs to."},"required":false,"description":"Filter by identifier of the project the order belongs to.","name":"projectId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by projectId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by projectId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"projectIds","in":"query"},{"schema":{"type":"string","format":"date-time","description":"Start of the overlap window (ISO 8601 with offset): returns orders whose rental period overlaps [overlapsFrom, overlapsTo]."},"required":false,"description":"Start of the overlap window (ISO 8601 with offset): returns orders whose rental period overlaps [overlapsFrom, overlapsTo].","name":"overlapsFrom","in":"query"},{"schema":{"type":"string","format":"date-time","description":"End of the overlap window (ISO 8601 with offset): returns orders whose rental period overlaps [overlapsFrom, overlapsTo]."},"required":false,"description":"End of the overlap window (ISO 8601 with offset): returns orders whose rental period overlaps [overlapsFrom, overlapsTo].","name":"overlapsTo","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by order number: exact match or prefix match."},"required":false,"description":"Filter by order number: exact match or prefix match.","name":"orderNumber","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Order number that matches exactly."},"required":false,"description":"Order number that matches exactly.","name":"orderNumberIs","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Order number that contains this text at any position."},"required":false,"description":"Order number that contains this text at any position.","name":"orderNumberContains","in":"query"},{"schema":{"description":"The order start date falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The order start date falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"startsOn","in":"query"},{"schema":{"description":"The order start date is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The order start date is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"startsAfter","in":"query"},{"schema":{"description":"The order start date is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The order start date is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"startsBefore","in":"query"},{"schema":{"description":"The order start date is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The order start date is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"startsFrom","in":"query"},{"schema":{"description":"The order start date is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The order start date is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"startsTo","in":"query"},{"schema":{"description":"The order end date falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The order end date falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"endsOn","in":"query"},{"schema":{"description":"The order end date is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The order end date is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"endsAfter","in":"query"},{"schema":{"description":"The order end date is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The order end date is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"endsBefore","in":"query"},{"schema":{"description":"The order end date is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The order end date is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"endsFrom","in":"query"},{"schema":{"description":"The order end date is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The order end date is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"endsTo","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderList"},"example":{"data":[{"id":"order_9f3a2b","orderNumber":"2026-0001","externalReference":"2026-0001","status":"draft","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","rentalDays":1,"projectId":"project_9f3a2b","projectName":"Example project name","contact":{"id":"contact_9f3a2b","name":"Example contact"},"itemsCount":1,"subTotalPrice":"120.00","discountTotal":"120.00","insuranceTotal":"120.00","depositTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"customFields":{"example":"example"},"source":"Example source","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/orders/list-orders"}},"post":{"operationId":"createOrder","tags":["Orders"],"summary":"Create an order","description":"Creates an order in DRAFT with the requested material. It is the validated equivalent of the project request inbox: it lets a web form, a CRM or an assistant request material for some dates.\n\nIt does NOT accept amounts of any kind (no prices, discounts, insurance or deposits): the order is born at zero and the team prices it from the application. Nor does it accept status, specific serialized units, accessories or notes.\n\nEvery referenced identifier (customer, items, project) is resolved against the account of the key BEFORE writing anything: a single one that does not belong to the account rejects the whole request with 400 and creates nothing.\n\n**Required scope:** `orders:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"orders:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderCreateBody"},"example":{"contactId":"cont_8f2a1c","startDate":"2026-09-01T08:00:00Z","endDate":"2026-09-05T20:00:00Z","lines":[{"itemId":"item_3b91de","quantity":2},{"itemId":"item_7c04af","quantity":1,"variantId":"var_11"}]}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderDetailResponse"},"example":{"data":{"id":"order_9f3a2b","orderNumber":"2026-0001","externalReference":"2026-0001","status":"draft","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","rentalDays":1,"projectId":"project_9f3a2b","projectName":"Example project name","contact":{"id":"contact_9f3a2b","name":"Example contact"},"itemsCount":1,"subTotalPrice":"120.00","discountTotal":"120.00","insuranceTotal":"120.00","depositTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"customFields":{"example":"example"},"source":"Example source","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","billingAddress":{"label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES"},"shippingAddress":{"label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES"},"contactPerson":{"id":"contact_person_9f3a2b","name":"Example contact person"},"quotes":[{"id":"quote_9f3a2b","number":"2026-0001","status":"Example status"}],"invoices":[{"id":"invoice_9f3a2b","number":"2026-0001","status":"Example status"}],"proformas":[{"id":"proforma_9f3a2b","number":"2026-0001","status":"Example status"}]}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/orders/create-an-order"}}},"/api/v1/orders/{orderId}":{"get":{"operationId":"getOrder","tags":["Orders"],"summary":"Get an order","description":"Returns the detail of an order. The `status` field emits the raw status (12 database values).\n\n**Required scope:** `orders:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"orders:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Order identifier."},"required":true,"description":"Order identifier.","name":"orderId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderDetailResponse"},"example":{"data":{"id":"order_9f3a2b","orderNumber":"2026-0001","externalReference":"2026-0001","status":"draft","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","rentalDays":1,"projectId":"project_9f3a2b","projectName":"Example project name","contact":{"id":"contact_9f3a2b","name":"Example contact"},"itemsCount":1,"subTotalPrice":"120.00","discountTotal":"120.00","insuranceTotal":"120.00","depositTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"customFields":{"example":"example"},"source":"Example source","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","billingAddress":{"label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES"},"shippingAddress":{"label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES"},"contactPerson":{"id":"contact_person_9f3a2b","name":"Example contact person"},"quotes":[{"id":"quote_9f3a2b","number":"2026-0001","status":"Example status"}],"invoices":[{"id":"invoice_9f3a2b","number":"2026-0001","status":"Example status"}],"proformas":[{"id":"proforma_9f3a2b","number":"2026-0001","status":"Example status"}]}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/orders/get-an-order"}},"patch":{"operationId":"updateOrder","tags":["Orders"],"summary":"Update the header of an order","description":"Changes the header of an order: customer, project and rental dates (send only the fields to change; the rest stay as they were). Changing `startDate` or `endDate` moves the WHOLE order: every line that inherits the order period moves with it (sections, type groups and lines already checked in keep theirs), together with its stock reservations and its delivery and return tasks; prices are not recalculated. If the stock does not fit the new period, or the order is cancelled or returned, it responds 409 `conflict` and nothing is written; sending the dates it already has changes nothing. It does NOT add, remove or edit lines: that goes through the editor. It does not accept amounts or status either, just like creation. The customer and the project are checked against the account of the API key before writing anything. Returns the full order, the same projection as its GET.\n\n**Required scope:** `orders:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"orders:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Order identifier."},"required":true,"description":"Order identifier.","name":"orderId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderUpdateBody"},"example":{"projectId":"prj_rodaje_otono","startDate":"2026-09-08T08:00:00+02:00","endDate":"2026-09-12T20:00:00+02:00"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderDetailResponse"},"example":{"data":{"id":"order_9f3a2b","orderNumber":"2026-0001","externalReference":"2026-0001","status":"draft","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","rentalDays":1,"projectId":"project_9f3a2b","projectName":"Example project name","contact":{"id":"contact_9f3a2b","name":"Example contact"},"itemsCount":1,"subTotalPrice":"120.00","discountTotal":"120.00","insuranceTotal":"120.00","depositTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"customFields":{"example":"example"},"source":"Example source","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","billingAddress":{"label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES"},"shippingAddress":{"label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES"},"contactPerson":{"id":"contact_person_9f3a2b","name":"Example contact person"},"quotes":[{"id":"quote_9f3a2b","number":"2026-0001","status":"Example status"}],"invoices":[{"id":"invoice_9f3a2b","number":"2026-0001","status":"Example status"}],"proformas":[{"id":"proforma_9f3a2b","number":"2026-0001","status":"Example status"}]}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/orders/update-the-header-of-an-order"}}},"/api/v1/orders/{orderId}/lines":{"get":{"operationId":"listOrderLines","tags":["Orders"],"summary":"List the lines of an order","description":"Returns which resources the order carries (items, spaces, services and custom elements) with their quantities, their specific serialized units, their period and their sale price. It is the usual query after getting an order. Lines added during delivery are left out unless requested with `includeDelivery=true`. It emits no cost or margin data. Lines belong to the order and are only obtained through it: there is no independent collection of lines. Lines come in document order.\n\n**Required scope:** `orders:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"orders:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Order identifier."},"required":true,"description":"Order identifier.","name":"orderId","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: position, itemName, quantity, startDate, endDate, rentalDays, unitPrice, linePrice, status, resourceType, transactionType. Defaults to \"position\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: position, itemName, quantity, startDate, endDate, rentalDays, unitPrice, linePrice, status, resourceType, transactionType. Defaults to \"position\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["item","kit","space","vehicle","personnel","service","custom","section","type_group"],"description":"Filter by line resource type: item, space, service, custom, section or type_group."},"required":false,"description":"Filter by line resource type: item, space, service, custom, section or type_group.","name":"resourceType","in":"query"},{"schema":{"type":"string","enum":["rental","sale"],"description":"Filter by line nature: rental or sale."},"required":false,"description":"Filter by line nature: rental or sale.","name":"transactionType","in":"query"},{"schema":{"type":"boolean","default":false,"description":"If \"true\", also includes the lines added during the delivery process. By default only the lines of the original order are returned."},"required":false,"description":"If \"true\", also includes the lines added during the delivery process. By default only the lines of the original order are returned.","name":"includeDelivery","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderLineList"},"example":{"data":[{"id":"order_line_9f3a2b","orderId":"order_9f3a2b","resourceType":"item","transactionType":"rental","status":"draft","position":1,"addedDuringDelivery":true,"itemId":"item_9f3a2b","itemName":"Example item name","variantId":"variant_9f3a2b","spaceId":"space_9f3a2b","quantity":1,"serials":[{"id":"serial_9f3a2b","code":"Example code","serialNumber":"2026-0001"}],"startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","rentalDays":1,"unitPrice":"120.00","linePrice":"120.00","free":true,"notes":"Example text."}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/orders/list-the-lines-of-an-order"}}},"/api/v1/invoices":{"get":{"operationId":"listInvoices","tags":["Invoices"],"summary":"List invoices","description":"Returns the issued invoices (invoice-type documents only), cursor-paginated. Filter by document or payment status. Strict per-subscription tenancy.\n\n**Required scope:** `invoices:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"invoices:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdOn","in":"query"},{"schema":{"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdAfter","in":"query"},{"schema":{"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdBefore","in":"query"},{"schema":{"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdFrom","in":"query"},{"schema":{"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdTo","in":"query"},{"schema":{"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedOn","in":"query"},{"schema":{"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedAfter","in":"query"},{"schema":{"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedBefore","in":"query"},{"schema":{"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedFrom","in":"query"},{"schema":{"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedTo","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, invoiceNumber, invoiceDate, dueDate, subTotal, grossPrice. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, invoiceNumber, invoiceDate, dueDate, subTotal, grossPrice. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["unpaid","partially_paid","paid","overpaid","overdue","voided"],"description":"Filter by payment status, with the same vocabulary the `paymentStatus` field returns: unpaid (nothing collected yet), partially_paid, paid, overpaid (collected above the total), overdue (past due and unpaid) or voided (the document is voided)."},"required":false,"description":"Filter by payment status, with the same vocabulary the `paymentStatus` field returns: unpaid (nothing collected yet), partially_paid, paid, overpaid (collected above the total), overdue (past due and unpaid) or voided (the document is voided).","name":"paymentStatus","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["unpaid","partially_paid","paid","overpaid","overdue","voided"]},"minItems":1,"maxItems":50,"description":"Filter by paymentStatus, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by paymentStatus, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"paymentStatuses","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by invoice contact identifier."},"required":false,"description":"Filter by invoice contact identifier.","name":"contactId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by contactId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by contactId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"contactIds","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by identifier of the source order of the invoice."},"required":false,"description":"Filter by identifier of the source order of the invoice.","name":"orderId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by orderId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by orderId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"orderIds","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by identifier of the project linked to the invoice."},"required":false,"description":"Filter by identifier of the project linked to the invoice.","name":"projectId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by projectId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by projectId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"projectIds","in":"query"},{"schema":{"description":"The invoice issue date falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The invoice issue date falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"invoiceDateOn","in":"query"},{"schema":{"description":"The invoice issue date is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The invoice issue date is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"invoiceDateAfter","in":"query"},{"schema":{"description":"The invoice issue date is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The invoice issue date is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"invoiceDateBefore","in":"query"},{"schema":{"description":"The invoice issue date is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The invoice issue date is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"invoiceDateFrom","in":"query"},{"schema":{"description":"The invoice issue date is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The invoice issue date is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"invoiceDateTo","in":"query"},{"schema":{"description":"The invoice due date falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The invoice due date falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"dueOn","in":"query"},{"schema":{"description":"The invoice due date is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The invoice due date is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"dueAfter","in":"query"},{"schema":{"description":"The invoice due date is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The invoice due date is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"dueBefore","in":"query"},{"schema":{"description":"The invoice due date is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The invoice due date is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"dueFrom","in":"query"},{"schema":{"description":"The invoice due date is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The invoice due date is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"dueTo","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceList"},"example":{"data":[{"id":"invoice_9f3a2b","invoiceNumber":"2026-0001","status":"draft","isRectification":true,"invoiceDate":"2026-09-01T08:00:00.000Z","dueDate":"2026-09-01T08:00:00.000Z","currency":"EUR","contact":{"id":"contact_9f3a2b","name":"Example contact"},"orderId":"order_9f3a2b","orderNumber":"2026-0001","projectId":"project_9f3a2b","subTotal":"120.00","discountTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","totalPaid":"120.00","paymentStatus":"unpaid","paymentMethod":"Example payment method","tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/invoices/list-invoices"}}},"/api/v1/invoices/{invoiceId}":{"get":{"operationId":"getInvoice","tags":["Invoices"],"summary":"Get an invoice","description":"Returns the detail of an invoice by its identifier.\n\n**Required scope:** `invoices:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"invoices:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Invoice identifier."},"required":true,"description":"Invoice identifier.","name":"invoiceId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceDetailResponse"},"example":{"data":{"id":"invoice_9f3a2b","invoiceNumber":"2026-0001","status":"draft","isRectification":true,"invoiceDate":"2026-09-01T08:00:00.000Z","dueDate":"2026-09-01T08:00:00.000Z","currency":"EUR","contact":{"id":"contact_9f3a2b","name":"Example contact"},"orderId":"order_9f3a2b","orderNumber":"2026-0001","projectId":"project_9f3a2b","subTotal":"120.00","discountTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","totalPaid":"120.00","paymentStatus":"unpaid","paymentMethod":"Example payment method","tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","projectName":"Example project name","taxBreakdown":[{"taxType":"120.00","label":"Main","rate":1,"baseAmount":"120.00","amount":"120.00"}],"productDiscountTotal":"120.00","globalDiscountTotal":"120.00","insuranceTotal":"120.00","depositTotal":"120.00","exchangeRate":1,"billingAddress":{"label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES"},"sourceQuoteIds":["source_quote_9f3a2b"],"sourceProformaIds":["source_proforma_9f3a2b"]}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/invoices/get-an-invoice"}}},"/api/v1/quotes":{"get":{"operationId":"listQuotes","tags":["Quotes"],"summary":"List quotes","description":"Returns the quotes with their active version flattened, cursor-paginated. Filter by commercial or operational status. Strict per-subscription tenancy.\n\n**Required scope:** `quotes:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"quotes:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdOn","in":"query"},{"schema":{"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdAfter","in":"query"},{"schema":{"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdBefore","in":"query"},{"schema":{"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdFrom","in":"query"},{"schema":{"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdTo","in":"query"},{"schema":{"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedOn","in":"query"},{"schema":{"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedAfter","in":"query"},{"schema":{"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedBefore","in":"query"},{"schema":{"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedFrom","in":"query"},{"schema":{"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedTo","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":200,"description":"Free-text search on the quote number, the order number, the notes, the header text and the client name."},"required":false,"description":"Free-text search on the quote number, the order number, the notes, the header text and the client name.","name":"q","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, quoteNumber, issueDate, startDate, endDate, subTotal, grossPrice, operativeStatus. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, quoteNumber, issueDate, startDate, endDate, subTotal, grossPrice, operativeStatus. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["pending","confirmed","cancelled","superseded"],"description":"Filter by commercial status of the active version: pending (awaiting an answer), confirmed (accepted), cancelled (rejected/cancelled) or superseded (replaced by another version)."},"required":false,"description":"Filter by commercial status of the active version: pending (awaiting an answer), confirmed (accepted), cancelled (rejected/cancelled) or superseded (replaced by another version).","name":"operativeStatus","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["pending","confirmed","cancelled","superseded"]},"minItems":1,"maxItems":50,"description":"Filter by operativeStatus, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by operativeStatus, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"operativeStatuses","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by quote contact identifier."},"required":false,"description":"Filter by quote contact identifier.","name":"contactId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by contactId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by contactId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"contactIds","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by identifier of the order linked to the quote."},"required":false,"description":"Filter by identifier of the order linked to the quote.","name":"orderId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by orderId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by orderId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"orderIds","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by identifier of the project linked to the quote."},"required":false,"description":"Filter by identifier of the project linked to the quote.","name":"projectId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by projectId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by projectId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"projectIds","in":"query"},{"schema":{"description":"The quote issue date falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The quote issue date falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"issueDateOn","in":"query"},{"schema":{"description":"The quote issue date is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The quote issue date is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"issueDateAfter","in":"query"},{"schema":{"description":"The quote issue date is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The quote issue date is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"issueDateBefore","in":"query"},{"schema":{"description":"The quote issue date is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The quote issue date is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"issueDateFrom","in":"query"},{"schema":{"description":"The quote issue date is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The quote issue date is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"issueDateTo","in":"query"},{"schema":{"description":"The quote validity date falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The quote validity date falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"validUntilOn","in":"query"},{"schema":{"description":"The quote validity date is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The quote validity date is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"validUntilAfter","in":"query"},{"schema":{"description":"The quote validity date is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The quote validity date is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"validUntilBefore","in":"query"},{"schema":{"description":"The quote validity date is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The quote validity date is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"validUntilFrom","in":"query"},{"schema":{"description":"The quote validity date is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The quote validity date is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"validUntilTo","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteList"},"example":{"data":[{"id":"quote_9f3a2b","quoteNumber":"2026-0001","versionNumber":1,"status":"draft","operativeStatus":"pending","issueDate":"2026-09-01T08:00:00.000Z","validUntil":"2026-09-01T08:00:00.000Z","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","currency":"EUR","contact":{"id":"contact_9f3a2b","name":"Example contact"},"orderId":"order_9f3a2b","orderNumber":"2026-0001","projectId":"project_9f3a2b","subTotal":"120.00","discountTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","totalPaid":"120.00","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/quotes/list-quotes"}}},"/api/v1/quotes/{quoteId}":{"get":{"operationId":"getQuote","tags":["Quotes"],"summary":"Get a quote","description":"Returns the detail of a quote with its active version flattened (document and commercial status).\n\n**Required scope:** `quotes:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"quotes:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Quote identifier."},"required":true,"description":"Quote identifier.","name":"quoteId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteDetailResponse"},"example":{"data":{"id":"quote_9f3a2b","quoteNumber":"2026-0001","versionNumber":1,"status":"draft","operativeStatus":"pending","issueDate":"2026-09-01T08:00:00.000Z","validUntil":"2026-09-01T08:00:00.000Z","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","currency":"EUR","contact":{"id":"contact_9f3a2b","name":"Example contact"},"orderId":"order_9f3a2b","orderNumber":"2026-0001","projectId":"project_9f3a2b","subTotal":"120.00","discountTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","totalPaid":"120.00","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","projectName":"Example project name","taxBreakdown":[{"taxType":"120.00","label":"Main","rate":1,"baseAmount":"120.00","amount":"120.00"}]}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/quotes/get-a-quote"}}},"/api/v1/projects":{"get":{"operationId":"listProjects","tags":["Projects"],"summary":"List projects","description":"Returns the projects that group orders and work, cursor-paginated. Tenancy inherited from the parent account: a billing account also sees the projects of its parent account.\n\n**Required scope:** `projects:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"projects:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdOn","in":"query"},{"schema":{"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdAfter","in":"query"},{"schema":{"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdBefore","in":"query"},{"schema":{"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdFrom","in":"query"},{"schema":{"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdTo","in":"query"},{"schema":{"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedOn","in":"query"},{"schema":{"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedAfter","in":"query"},{"schema":{"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedBefore","in":"query"},{"schema":{"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedFrom","in":"query"},{"schema":{"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedTo","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":200,"description":"Free-text search on the name and the external reference."},"required":false,"description":"Free-text search on the name and the external reference.","name":"q","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, name, projectNumber, startDate, endDate, status. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, name, projectNumber, startDate, endDate, status. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["draft","budgeted","confirmed","in_progress","invoiced","completed","cancelled","archived"],"description":"Filter by project status: draft, budgeted, confirmed, in_progress, invoiced, completed, cancelled or archived (legacy status present in old data)."},"required":false,"description":"Filter by project status: draft, budgeted, confirmed, in_progress, invoiced, completed, cancelled or archived (legacy status present in old data).","name":"status","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by project contact identifier."},"required":false,"description":"Filter by project contact identifier.","name":"contactId","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by project type identifier."},"required":false,"description":"Filter by project type identifier.","name":"projectTypeId","in":"query"},{"schema":{"type":"boolean","description":"Filter by archived: \"true\" lists ONLY archived projects; \"false\" (or absent) excludes them from the listing."},"required":false,"description":"Filter by archived: \"true\" lists ONLY archived projects; \"false\" (or absent) excludes them from the listing.","name":"archived","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectList"},"example":{"data":[{"id":"project_9f3a2b","projectNumber":"2026-0001","name":"Example project","color":"Example color","externalReference":"2026-0001","projectTypeId":"project_type_9f3a2b","projectType":{"id":"project_type_9f3a2b","name":"Example project type","color":"Example color"},"contact":{"id":"contact_9f3a2b","name":"Example contact"},"location":{"name":"Example location","address":"Example address","city":"Madrid","postalCode":"28001","province":"Madrid","country":"ES","lat":1,"lng":1},"startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","status":"draft","archived":true,"orderIds":["order_9f3a2b"],"totalOrders":1,"tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"customFields":{"example":"example"},"source":"Example source","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/projects/list-projects"}},"post":{"operationId":"createProject","tags":["Projects"],"summary":"Create a project","description":"Creates a project in DRAFT: the container of the work, with its name, its dates and optionally its customer and its type. The name needs at least three characters.\n\nIt does not accept status, images, tags, additional contacts or location: decorating the project is up to the application. The customer and the project type are checked against the account of the API key before creating anything. Returns the full project, the same projection as its GET.\n\n**Required scope:** `projects:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"projects:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectCreateBody"},"example":{"name":"Rodaje Vega — spot de otoño","startDate":"2026-09-01T08:00:00Z","endDate":"2026-09-12T20:00:00Z","contactId":"cont_8f2a1c","externalReference":"CRM-2026-114","location":{"name":"Plató 2","city":"Pozuelo de Alarcón","province":"Madrid","country":"ES"}}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDetailResponse"},"example":{"data":{"id":"project_9f3a2b","projectNumber":"2026-0001","name":"Example project","color":"Example color","externalReference":"2026-0001","projectTypeId":"project_type_9f3a2b","projectType":{"id":"project_type_9f3a2b","name":"Example project type","color":"Example color"},"contact":{"id":"contact_9f3a2b","name":"Example contact"},"location":{"name":"Example location","address":"Example address","city":"Madrid","postalCode":"28001","province":"Madrid","country":"ES","lat":1,"lng":1},"startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","status":"draft","archived":true,"orderIds":["order_9f3a2b"],"totalOrders":1,"tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"customFields":{"example":"example"},"source":"Example source","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/projects/create-a-project"}}},"/api/v1/projects/{projectId}/archive":{"put":{"operationId":"archiveProject","tags":["Projects"],"summary":"Archive or restore a project","description":"Takes the project out of the active views or brings it back to them. It deletes nothing and touches neither the orders, nor the documents, nor the team: only the visibility. Only a draft or cancelled project can be archived (409 otherwise); restoring is always allowed. PUT because the call SETS the value —there is no toggle—, so repeating it does nothing new. Responds 204 with no body. An archived project is left out of the listing unless `archived=true` is passed; its GET keeps answering with `archived: true`.\n\n**Required scope:** `projects:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"projects:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Project identifier."},"required":true,"description":"Project identifier.","name":"projectId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectArchiveBody"},"example":{"archived":true}}}},"responses":{"204":{"description":"No content.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/projects/archive-or-restore-a-project"}}},"/api/v1/projects/{projectId}":{"get":{"operationId":"getProject","tags":["Projects"],"summary":"Get a project","description":"Returns the detail of a project by its identifier.\n\n**Required scope:** `projects:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"projects:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Project identifier."},"required":true,"description":"Project identifier.","name":"projectId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDetailResponse"},"example":{"data":{"id":"project_9f3a2b","projectNumber":"2026-0001","name":"Example project","color":"Example color","externalReference":"2026-0001","projectTypeId":"project_type_9f3a2b","projectType":{"id":"project_type_9f3a2b","name":"Example project type","color":"Example color"},"contact":{"id":"contact_9f3a2b","name":"Example contact"},"location":{"name":"Example location","address":"Example address","city":"Madrid","postalCode":"28001","province":"Madrid","country":"ES","lat":1,"lng":1},"startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","status":"draft","archived":true,"orderIds":["order_9f3a2b"],"totalOrders":1,"tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"customFields":{"example":"example"},"source":"Example source","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/projects/get-a-project"}},"patch":{"operationId":"updateProject","tags":["Projects"],"summary":"Update a project","description":"Changes the record of a project: name, dates, customer, type, external reference, location and color (send only the fields to change). It does NOT change the status, the archiving or the linked orders: links have their own sub-resource. An archived project is read-only: the request is rejected with 409 `conflict` and nothing is written; unarchive it first with `PUT /api/v1/projects/{projectId}/archive` and `archived: false`. The customer and the project type are checked against the account of the API key before writing anything. Returns the full project, the same projection as its GET.\n\n**Required scope:** `projects:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"projects:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Project identifier."},"required":true,"description":"Project identifier.","name":"projectId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectUpdateBody"},"example":{"startDate":"2026-09-08T08:00:00+02:00","endDate":"2026-09-19T20:00:00+02:00","externalReference":"CRM-2026-114","location":{"name":"Plató 2","address":"Ciudad de la Imagen","city":"Pozuelo de Alarcón","province":"Madrid","country":"ES"}}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDetailResponse"},"example":{"data":{"id":"project_9f3a2b","projectNumber":"2026-0001","name":"Example project","color":"Example color","externalReference":"2026-0001","projectTypeId":"project_type_9f3a2b","projectType":{"id":"project_type_9f3a2b","name":"Example project type","color":"Example color"},"contact":{"id":"contact_9f3a2b","name":"Example contact"},"location":{"name":"Example location","address":"Example address","city":"Madrid","postalCode":"28001","province":"Madrid","country":"ES","lat":1,"lng":1},"startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","status":"draft","archived":true,"orderIds":["order_9f3a2b"],"totalOrders":1,"tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"customFields":{"example":"example"},"source":"Example source","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/projects/update-a-project"}}},"/api/v1/invoices/{invoiceId}/payments":{"get":{"operationId":"listInvoicePayments","tags":["Invoices"],"summary":"List the payments of an invoice","description":"Returns the treasury payments assigned to an invoice, newest first, with the same projection as `GET /api/v1/treasury/payments/{paymentId}`. What it reads are treasury payments, so it takes the treasury scope, not the invoices one. The invoice must belong to the account: an unknown or foreign invoice is a 404, not an empty list.\n\n**Required scope:** `treasury:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"treasury:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Invoice identifier."},"required":true,"description":"Invoice identifier.","name":"invoiceId","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: a single field, with a leading \"-\" for descending (e.g. \"-updatedAt\"). Sortable fields: date, amount, createdAt, updatedAt. Defaults to \"-date\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: a single field, with a leading \"-\" for descending (e.g. \"-updatedAt\"). Sortable fields: date, amount, createdAt, updatedAt. Defaults to \"-date\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentList"},"example":{"data":[{"id":"payment_9f3a2b","direction":"Example direction","amount":"120.00","currency":"EUR","date":"2026-09-01T08:00:00.000Z","type":"Example type","treasuryAccountId":"treasury_account_9f3a2b","contactId":"contact_9f3a2b","reference":"2026-0001","linkedDocuments":[{"type":"invoice","id":"linked_document_9f3a2b","amount":"120.00"}],"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/invoices/list-the-payments-of-an-invoice"}}},"/api/v1/invoices/{invoiceId}/lines":{"get":{"operationId":"listInvoiceLines","tags":["Invoices"],"summary":"List the lines of an invoice","description":"Returns what was invoiced, line by line, with its quantity and its price. The names are the ones FROZEN when the invoice was issued and may differ from the current catalog: the document is a snapshot. It emits no per-line tax configuration; the invoice totals already carry the calculated taxes. Lines come in document order.\n\n**Required scope:** `invoices:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"invoices:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Invoice identifier."},"required":true,"description":"Invoice identifier.","name":"invoiceId","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: position, itemName, quantity, startDate, endDate, rentalDays, unitPrice, linePrice, resourceType, transactionType. Defaults to \"position\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: position, itemName, quantity, startDate, endDate, rentalDays, unitPrice, linePrice, resourceType, transactionType. Defaults to \"position\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentLineList"},"example":{"data":[{"id":"document_line_9f3a2b","resourceType":"item","transactionType":"rental","position":1,"itemId":"item_9f3a2b","itemName":"Example item name","variantId":"variant_9f3a2b","variantName":"Example variant name","quantity":1,"orderId":"order_9f3a2b","orderNumber":"2026-0001","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","rentalDays":1,"unitPrice":"120.00","linePrice":"120.00","free":true,"notes":"Example text."}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/invoices/list-the-lines-of-an-invoice"}}},"/api/v1/quotes/{quoteId}/lines":{"get":{"operationId":"listQuoteLines","tags":["Quotes"],"summary":"List the lines of a quote","description":"Returns what was quoted, line by line, with its quantity and its price. They belong to the ACTIVE VERSION of the quote, like the rest of the resource. Lines come in document order.\n\n**Required scope:** `quotes:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"quotes:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Quote identifier."},"required":true,"description":"Quote identifier.","name":"quoteId","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: position, itemName, quantity, startDate, endDate, rentalDays, unitPrice, linePrice, resourceType, transactionType. Defaults to \"position\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: position, itemName, quantity, startDate, endDate, rentalDays, unitPrice, linePrice, resourceType, transactionType. Defaults to \"position\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentLineList"},"example":{"data":[{"id":"document_line_9f3a2b","resourceType":"item","transactionType":"rental","position":1,"itemId":"item_9f3a2b","itemName":"Example item name","variantId":"variant_9f3a2b","variantName":"Example variant name","quantity":1,"orderId":"order_9f3a2b","orderNumber":"2026-0001","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","rentalDays":1,"unitPrice":"120.00","linePrice":"120.00","free":true,"notes":"Example text."}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/quotes/list-the-lines-of-a-quote"}}},"/api/v1/serialized-items":{"get":{"operationId":"listSerializedItems","tags":["Items"],"summary":"List serialized items","description":"Returns the specific physical units of the inventory with their serial number, their status and which order they are committed to right now. Filter by `itemId` to keep those of one catalog item. It is the piece that lets an external system know which unit is where. It emits no purchase prices or supplier agreements.\n\n**Required scope:** `items:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"items:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdOn","in":"query"},{"schema":{"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdAfter","in":"query"},{"schema":{"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdBefore","in":"query"},{"schema":{"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdFrom","in":"query"},{"schema":{"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdTo","in":"query"},{"schema":{"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedOn","in":"query"},{"schema":{"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedAfter","in":"query"},{"schema":{"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedBefore","in":"query"},{"schema":{"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedFrom","in":"query"},{"schema":{"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedTo","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, code, serialNumber, status, condition, itemName. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, code, serialNumber, status, condition, itemName. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by catalog item: returns only its physical units."},"required":false,"description":"Filter by catalog item: returns only its physical units.","name":"itemId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by itemId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by itemId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"itemIds","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by warehouse or space where the unit is located."},"required":false,"description":"Filter by warehouse or space where the unit is located.","name":"spaceId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by spaceId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by spaceId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"spaceIds","in":"query"},{"schema":{"type":"string","enum":["available","prepared","picked_up","returned","broken","archived","sold"],"description":"Filter by unit status. If omitted, all are returned."},"required":false,"description":"Filter by unit status. If omitted, all are returned.","name":"status","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["available","prepared","picked_up","returned","broken","archived","sold"],"description":"Estado del item serializado: disponible, preparado, recogido, descargado, roto, archivado o vendido"},"minItems":1,"maxItems":50,"description":"Filter by status, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by status, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"statuses","in":"query"},{"schema":{"type":"string","enum":["regular","temporary"],"description":"Filter by inventory type: \"regular\" is own stock, \"temporary\" is stock brought in for a specific job (subrent). If omitted, both are returned."},"required":false,"description":"Filter by inventory type: \"regular\" is own stock, \"temporary\" is stock brought in for a specific job (subrent). If omitted, both are returned.","name":"inventoryType","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["regular","temporary"]},"minItems":1,"maxItems":50,"description":"Filter by inventoryType, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by inventoryType, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"inventoryTypes","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SerializedItemList"},"example":{"data":[{"id":"serialized_item_9f3a2b","code":"Example code","serialNumber":"2026-0001","status":"Example status","condition":"Example condition","inventoryType":"Example inventory type","itemId":"item_9f3a2b","itemName":"Example item name","itemSku":"Example item sku","variantId":"variant_9f3a2b","variantName":"Example variant name","currentOrderId":"current_order_9f3a2b","currentOrderNumber":"2026-0001","projectId":"project_9f3a2b","contactId":"contact_9f3a2b","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/items/list-serialized-items"}}},"/api/v1/serialized-items/{serializedItemId}":{"get":{"operationId":"getSerializedItem","tags":["Items"],"summary":"Get a serialized item","description":"Returns the record of a specific physical unit: its code, its serial number, its status and the catalog item it is a unit of. It is narrower than the listing on purpose. The line history and the incidents of the unit are not emitted here.\n\n**Required scope:** `items:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"items:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Serialized item identifier."},"required":true,"description":"Serialized item identifier.","name":"serializedItemId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SerializedItemDetailResponse"},"example":{"data":{"id":"serialized_item_9f3a2b","code":"Example code","serialNumber":"2026-0001","status":"Example status","itemId":"item_9f3a2b","itemName":"Example item name","itemSku":"Example item sku","itemCollectionName":"Example item collection name","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/items/get-a-serialized-item"}},"patch":{"operationId":"updateSerializedItem","tags":["Items"],"summary":"Update a serialized item","description":"Changes the record of ONE serialized item: its status, where it is, its serial number or its warranty. It is what a warehouse system needs to say \"this one is back and operational\". What the unit cost, the internal note and the subrent terms neither go in nor come out through this API. The item it belongs to is resolved by the server. Returns the full serialized item, the same projection as its GET.\n\n**Required scope:** `items:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"items:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Serialized item identifier."},"required":true,"description":"Serialized item identifier.","name":"serializedItemId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SerializedItemUpdateBody"},"example":{"status":"available","active":true,"spaceId":"spc_almacen_central","locationId":"loc_estante_b3","orderInfo":"Revisada tras la reparación de septiembre"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SerializedItemDetailResponse"},"example":{"data":{"id":"serialized_item_9f3a2b","code":"Example code","serialNumber":"2026-0001","status":"Example status","itemId":"item_9f3a2b","itemName":"Example item name","itemSku":"Example item sku","itemCollectionName":"Example item collection name","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/items/update-a-serialized-item"}}},"/api/v1/spaces":{"get":{"operationId":"listSpaces","tags":["Spaces"],"summary":"List warehouses and spaces","description":"Returns the warehouses and rentable spaces of the account, cursor-paginated. A space with `isWarehouse: true` is a warehouse that manages stock; with `false` it is a rentable space (a studio, a room). Filter by `isWarehouse` to keep one kind or the other. It emits no costs or pricing configuration.\n\n**Required scope:** `spaces:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"spaces:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdOn","in":"query"},{"schema":{"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdAfter","in":"query"},{"schema":{"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdBefore","in":"query"},{"schema":{"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdFrom","in":"query"},{"schema":{"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdTo","in":"query"},{"schema":{"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedOn","in":"query"},{"schema":{"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedAfter","in":"query"},{"schema":{"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedBefore","in":"query"},{"schema":{"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedFrom","in":"query"},{"schema":{"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedTo","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, name, internalReference, isWarehouse, building, floor. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, name, internalReference, isWarehouse, building, floor. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"boolean","description":"Filter by space nature: \"true\" returns only warehouses (those that manage stock), \"false\" only rentable spaces. If omitted, both are returned."},"required":false,"description":"Filter by space nature: \"true\" returns only warehouses (those that manage stock), \"false\" only rentable spaces. If omitted, both are returned.","name":"isWarehouse","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by identifier of the collection the space belongs to."},"required":false,"description":"Filter by identifier of the collection the space belongs to.","name":"collectionId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by collectionId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by collectionId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"collectionIds","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpaceList"},"example":{"data":[{"id":"space_9f3a2b","name":"Example space","internalReference":"2026-0001","isWarehouse":true,"collectionId":"collection_9f3a2b","collectionName":"Example collection name","building":"Example building","floor":1,"location":{"address":"Example address","city":"Madrid","postalCode":"28001","country":"ES","lat":1,"lng":1},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/spaces/list-warehouses-and-spaces"}}},"/api/v1/spaces/{spaceId}":{"delete":{"operationId":"deleteSpace","tags":["Spaces"],"summary":"Delete a space","description":"Deletes the space and everything hanging from it: its notes, files, tasks, images and declared unavailabilities. It is NOT reversible. Responds 409 if inventory (serialized units or bulk stock) is located in the space, or if it has future availability rules from a schedule: move the inventory, or retire the schedule, first. Responds 204 with no body: the space no longer exists for the API (its GET responds 404).\n\n**Required scope:** `spaces:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"spaces:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Space identifier."},"required":true,"description":"Space identifier.","name":"spaceId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"responses":{"204":{"description":"No content.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/spaces/delete-a-space"}},"get":{"operationId":"getSpace","tags":["Spaces"],"summary":"Get a warehouse or space","description":"Returns the detail of a warehouse or space by its identifier, with its capacity, surface area, amenities and custom fields.\n\n**Required scope:** `spaces:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"spaces:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Space identifier."},"required":true,"description":"Space identifier.","name":"spaceId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpaceDetailResponse"},"example":{"data":{"id":"space_9f3a2b","name":"Example space","internalReference":"2026-0001","isWarehouse":true,"collectionId":"collection_9f3a2b","collectionName":"Example collection name","building":"Example building","floor":1,"location":{"address":"Example address","city":"Madrid","postalCode":"28001","country":"ES","lat":1,"lng":1},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","description":"Example text.","capacity":1,"area":1,"dimensions":"Example dimensions","amenities":["Example amenities"],"equipments":["Example equipments"],"pricingSettings":{"type":"periodPrice","price":"120.00","period":"hour"},"insuranceEnabled":true,"discountEnabled":true,"depositValue":"120.00","bufferBefore":1,"bufferBeforeUnit":"hour","bufferAfter":1,"bufferAfterUnit":"hour","customFields":{"example":"example"}}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/spaces/get-a-warehouse-or-space"}},"patch":{"operationId":"updateSpace","tags":["Spaces"],"summary":"Update a warehouse or space","description":"Updates the record of a warehouse or space (send only the fields to change). `tags` replaces the whole list, and a tag name that does not exist CREATES it. The holding costs of the space are NOT part of the public contract and cannot be written here; for the rate there is the pricing endpoint. If another space of the account already has that `name` (without distinguishing upper and lower case) or that `internalReference`, it responds 409 `conflict` with `errors[0].path` on the field. Returns the updated space in detail.\n\n**Required scope:** `spaces:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"spaces:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Space identifier."},"required":true,"description":"Space identifier.","name":"spaceId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpaceUpdateBody"},"example":{"name":"Almacén Vallecas","building":"Nave 4","location":{"address":"Calle del Estor 8","city":"Madrid","postalCode":"28038","country":"ES","lat":40.3897,"lng":-3.6512},"area":420,"isWarehouse":true,"tags":["Madrid","Almacén"]}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpaceDetailResponse"},"example":{"data":{"id":"space_9f3a2b","name":"Example space","internalReference":"2026-0001","isWarehouse":true,"collectionId":"collection_9f3a2b","collectionName":"Example collection name","building":"Example building","floor":1,"location":{"address":"Example address","city":"Madrid","postalCode":"28001","country":"ES","lat":1,"lng":1},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","description":"Example text.","capacity":1,"area":1,"dimensions":"Example dimensions","amenities":["Example amenities"],"equipments":["Example equipments"],"pricingSettings":{"type":"periodPrice","price":"120.00","period":"hour"},"insuranceEnabled":true,"discountEnabled":true,"depositValue":"120.00","bufferBefore":1,"bufferBeforeUnit":"hour","bufferAfter":1,"bufferAfterUnit":"hour","customFields":{"example":"example"}}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/spaces/update-a-warehouse-or-space"}}},"/api/v1/spaces/{spaceId}/amenities":{"put":{"operationId":"replaceSpaceAmenities","tags":["Spaces"],"summary":"Replace the amenities and equipment","description":"Fully REPLACES the two lists of the space: the amenities offered with it (wifi, 24/7 access, parking) and the physical equipment delivered with it (projector, whiteboard, sound). It is PUT and not PATCH because both lists are replaced whole: always send both, including the one that does not change. Returns the updated space in detail.\n\n**Required scope:** `spaces:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"spaces:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Space identifier."},"required":true,"description":"Space identifier.","name":"spaceId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpaceAmenitiesBody"},"example":{"commodities":["Wifi","Acceso 24/7","Parking","Aseos"],"amenities":["Proyector","Pizarra","Equipo de sonido"]}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpaceDetailResponse"},"example":{"data":{"id":"space_9f3a2b","name":"Example space","internalReference":"2026-0001","isWarehouse":true,"collectionId":"collection_9f3a2b","collectionName":"Example collection name","building":"Example building","floor":1,"location":{"address":"Example address","city":"Madrid","postalCode":"28001","country":"ES","lat":1,"lng":1},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","description":"Example text.","capacity":1,"area":1,"dimensions":"Example dimensions","amenities":["Example amenities"],"equipments":["Example equipments"],"pricingSettings":{"type":"periodPrice","price":"120.00","period":"hour"},"insuranceEnabled":true,"discountEnabled":true,"depositValue":"120.00","bufferBefore":1,"bufferBeforeUnit":"hour","bufferAfter":1,"bufferAfterUnit":"hour","customFields":{"example":"example"}}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/spaces/replace-the-amenities-and-equipment"}}},"/api/v1/spaces/{spaceId}/pricing":{"patch":{"operationId":"updateSpacePricing","tags":["Spaces"],"summary":"Update the pricing of a space","description":"Sets the rental rate of the space, the deposit, whether it allows insurance and discount, and the time margins that block it around the booking. The internal cost, the external cost and the tax configuration are NOT part of the public contract. Note: the public record of a space does not emit its commercial policy, so what you write here cannot be read back through the API. Returns the updated space in detail.\n\n**Required scope:** `spaces:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"spaces:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Space identifier."},"required":true,"description":"Space identifier.","name":"spaceId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpacePricingBody"},"example":{"pricingSettings":{"type":"periodPrice","price":"90.00","period":"hour"},"depositValue":"500.00","insuranceEnabled":false,"discountEnabled":true,"bufferBefore":2,"bufferBeforeUnit":"hour","bufferAfter":2,"bufferAfterUnit":"hour"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpaceDetailResponse"},"example":{"data":{"id":"space_9f3a2b","name":"Example space","internalReference":"2026-0001","isWarehouse":true,"collectionId":"collection_9f3a2b","collectionName":"Example collection name","building":"Example building","floor":1,"location":{"address":"Example address","city":"Madrid","postalCode":"28001","country":"ES","lat":1,"lng":1},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","description":"Example text.","capacity":1,"area":1,"dimensions":"Example dimensions","amenities":["Example amenities"],"equipments":["Example equipments"],"pricingSettings":{"type":"periodPrice","price":"120.00","period":"hour"},"insuranceEnabled":true,"discountEnabled":true,"depositValue":"120.00","bufferBefore":1,"bufferBeforeUnit":"hour","bufferAfter":1,"bufferAfterUnit":"hour","customFields":{"example":"example"}}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/spaces/update-the-pricing-of-a-space"}}},"/api/v1/repair-tickets":{"get":{"operationId":"listRepairTickets","tags":["Repair tickets"],"summary":"List repair tickets","description":"Returns the repair tickets of the account, cursor-paginated: what broke, on which order it came back broken and what the customer is quoted to fix it. Amounts are sale amounts to the customer; the repair cost is not published.\n\n**Required scope:** `repair-tickets:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"repair-tickets:read","x-required-addon":["incidence"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdOn","in":"query"},{"schema":{"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdAfter","in":"query"},{"schema":{"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdBefore","in":"query"},{"schema":{"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdFrom","in":"query"},{"schema":{"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdTo","in":"query"},{"schema":{"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedOn","in":"query"},{"schema":{"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedAfter","in":"query"},{"schema":{"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedBefore","in":"query"},{"schema":{"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedFrom","in":"query"},{"schema":{"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedTo","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":200,"description":"Free-text search on the ticket number and the notes."},"required":false,"description":"Free-text search on the ticket number and the notes.","name":"q","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, date, status, total. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, date, status, total. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["draft","sent","partially_converted","fully_invoiced","closed"],"description":"Filter by ticket status: draft, sent, partially_converted, fully_invoiced or closed."},"required":false,"description":"Filter by ticket status: draft, sent, partially_converted, fully_invoiced or closed.","name":"status","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["draft","sent","partially_converted","fully_invoiced","closed"],"description":"Repair ticket status."},"minItems":1,"maxItems":50,"description":"Filter by status, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by status, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"statuses","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by identifier of the order the ticket comes from."},"required":false,"description":"Filter by identifier of the order the ticket comes from.","name":"orderId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by orderId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by orderId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"orderIds","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by identifier of the client responsible for the repair."},"required":false,"description":"Filter by identifier of the client responsible for the repair.","name":"contactId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by contactId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by contactId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"contactIds","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepairTicketList"},"example":{"data":[{"id":"repair_ticket_9f3a2b","number":"2026-0001","date":"2026-09-01T08:00:00.000Z","status":"draft","orderId":"order_9f3a2b","orderNumber":"2026-0001","contactId":"contact_9f3a2b","contactName":"Example contact name","subTotal":"120.00","taxTotal":"120.00","total":"120.00","totalLines":1,"notes":"Example text.","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/repair-tickets/list-repair-tickets"}},"post":{"operationId":"createRepairTicket","tags":["Repair tickets"],"summary":"Create a repair ticket","description":"Opens a repair ticket with its lines. `unitPrice` is what is quoted to the CUSTOMER; the repair cost for the company neither goes in nor comes out through this API. `incidentIds` converts existing incidents and the server ties each line to its own. Behind the `incidence` add-on: without it, 402. Returns the full repair ticket, the same projection as its GET.\n\n**Required scope:** `repair-tickets:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"repair-tickets:write","x-required-addon":["incidence"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepairTicketCreateBody"},"example":{"date":"2026-09-03T09:00:00+02:00","orderId":"ord_00421","contactId":"cont_00118","lines":[{"description":"Sustituir el anillo de zoom","diagnosis":"El anillo patina en el tramo largo tras la caída del rodaje","entityType":"item","entityId":"itm_00042","serializedItemId":"ser_00042_03","incidentId":"inc_00711","quantity":1,"unitPrice":"180.00"}]}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepairTicketDetailResponse"},"example":{"data":{"id":"repair_ticket_9f3a2b","number":"2026-0001","date":"2026-09-01T08:00:00.000Z","status":"draft","orderId":"order_9f3a2b","orderNumber":"2026-0001","contactId":"contact_9f3a2b","contactName":"Example contact name","subTotal":"120.00","taxTotal":"120.00","total":"120.00","totalLines":1,"notes":"Example text.","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","projectId":"project_9f3a2b","lines":[{"id":"line_9f3a2b","entityType":"item","entityId":"entity_9f3a2b","entityName":"Example entity name","description":"Example text.","diagnosis":"Example diagnosis","quantity":1,"unitPrice":"120.00","incidentId":"incident_9f3a2b","notes":"Example text."}],"sourceIncidentIds":["source_incident_9f3a2b"],"customFields":{"example":"example"}}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/repair-tickets/create-a-repair-ticket"}}},"/api/v1/repair-tickets/{ticketId}":{"get":{"operationId":"getRepairTicket","tags":["Repair tickets"],"summary":"Get a repair ticket","description":"Returns the detail of a repair ticket with its lines: which element is repaired, its diagnosis and its price for the customer.\n\n**Required scope:** `repair-tickets:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"repair-tickets:read","x-required-addon":["incidence"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Repair ticket identifier."},"required":true,"description":"Repair ticket identifier.","name":"ticketId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepairTicketDetailResponse"},"example":{"data":{"id":"repair_ticket_9f3a2b","number":"2026-0001","date":"2026-09-01T08:00:00.000Z","status":"draft","orderId":"order_9f3a2b","orderNumber":"2026-0001","contactId":"contact_9f3a2b","contactName":"Example contact name","subTotal":"120.00","taxTotal":"120.00","total":"120.00","totalLines":1,"notes":"Example text.","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","projectId":"project_9f3a2b","lines":[{"id":"line_9f3a2b","entityType":"item","entityId":"entity_9f3a2b","entityName":"Example entity name","description":"Example text.","diagnosis":"Example diagnosis","quantity":1,"unitPrice":"120.00","incidentId":"incident_9f3a2b","notes":"Example text."}],"sourceIncidentIds":["source_incident_9f3a2b"],"customFields":{"example":"example"}}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/repair-tickets/get-a-repair-ticket"}},"patch":{"operationId":"updateRepairTicket","tags":["Repair tickets"],"summary":"Update a repair ticket","description":"Changes the header of the repair ticket and, if you send `lines`, REPLACES the whole set of lines: send all of them or none. A `closed` ticket is read-only and is rejected; in a `partially_converted` or `fully_invoiced` one, the lines already converted to a purchase or an invoice are locked and changes to them are ignored. Behind the `incidence` add-on. Returns the full repair ticket, the same projection as its GET.\n\n**Required scope:** `repair-tickets:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"repair-tickets:write","x-required-addon":["incidence"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Repair ticket identifier."},"required":true,"description":"Repair ticket identifier.","name":"ticketId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepairTicketUpdateBody"},"example":{"status":"closed","notes":"Reparado en taller propio y devuelto al pool"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepairTicketDetailResponse"},"example":{"data":{"id":"repair_ticket_9f3a2b","number":"2026-0001","date":"2026-09-01T08:00:00.000Z","status":"draft","orderId":"order_9f3a2b","orderNumber":"2026-0001","contactId":"contact_9f3a2b","contactName":"Example contact name","subTotal":"120.00","taxTotal":"120.00","total":"120.00","totalLines":1,"notes":"Example text.","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","projectId":"project_9f3a2b","lines":[{"id":"line_9f3a2b","entityType":"item","entityId":"entity_9f3a2b","entityName":"Example entity name","description":"Example text.","diagnosis":"Example diagnosis","quantity":1,"unitPrice":"120.00","incidentId":"incident_9f3a2b","notes":"Example text."}],"sourceIncidentIds":["source_incident_9f3a2b"],"customFields":{"example":"example"}}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/repair-tickets/update-a-repair-ticket"}}},"/api/v1/vehicles":{"get":{"operationId":"listVehicles","tags":["Vehicles"],"summary":"List vehicles","description":"Returns the fleet used to deliver and pick up the material: operational status, license plate, seats and payload. It emits no operating costs or pricing configuration. Sorted by name.\n\n**Required scope:** `vehicles:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"vehicles:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdOn","in":"query"},{"schema":{"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdAfter","in":"query"},{"schema":{"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdBefore","in":"query"},{"schema":{"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdFrom","in":"query"},{"schema":{"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdTo","in":"query"},{"schema":{"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedOn","in":"query"},{"schema":{"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedAfter","in":"query"},{"schema":{"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedBefore","in":"query"},{"schema":{"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedFrom","in":"query"},{"schema":{"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedTo","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":200,"description":"Free-text search on the name and the registration number."},"required":false,"description":"Free-text search on the name and the registration number.","name":"q","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, name, registrationNumber, status, seats, payloadKg. Defaults to \"name\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, name, registrationNumber, status, seats, payloadKg. Defaults to \"name\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["active","maintenance","inactive"],"description":"Filter by vehicle status: active, maintenance or inactive."},"required":false,"description":"Filter by vehicle status: active, maintenance or inactive.","name":"status","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["active","maintenance","inactive"],"description":"Vehicle operational status: active, in maintenance or inactive."},"minItems":1,"maxItems":50,"description":"Filter by status, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by status, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"statuses","in":"query"},{"schema":{"description":"The next inspection of the vehicle falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The next inspection of the vehicle falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"inspectionOn","in":"query"},{"schema":{"description":"The next inspection of the vehicle is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The next inspection of the vehicle is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"inspectionAfter","in":"query"},{"schema":{"description":"The next inspection of the vehicle is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The next inspection of the vehicle is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"inspectionBefore","in":"query"},{"schema":{"description":"The next inspection of the vehicle is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The next inspection of the vehicle is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"inspectionFrom","in":"query"},{"schema":{"description":"The next inspection of the vehicle is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The next inspection of the vehicle is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"inspectionTo","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VehicleList"},"example":{"data":[{"id":"vehicle_9f3a2b","name":"Example vehicle","status":"active","registrationNumber":"2026-0001","seats":1,"payloadKg":1,"inspectionDate":"2026-09-01T08:00:00.000Z","collectionId":"collection_9f3a2b","collectionName":"Example collection name","showInPlanner":true,"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/vehicles/list-vehicles"}},"post":{"operationId":"createVehicle","tags":["Vehicles"],"summary":"Create a vehicle","description":"Registers a vehicle in the fleet. `collectionId` must be the UUID of an existing collection; tags go by name and one that does not exist is CREATED. Returns the created vehicle.\n\n**Required scope:** `vehicles:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"vehicles:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VehicleCreateBody"},"example":{"name":"Furgón Sprinter 1","registrationNumber":"1234 KLM","description":"Furgón de carga con portón trasero.","seats":3,"tags":["Flota","Madrid"]}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VehicleResponse"},"example":{"data":{"id":"vehicle_9f3a2b","name":"Example vehicle","status":"active","registrationNumber":"2026-0001","seats":1,"payloadKg":1,"inspectionDate":"2026-09-01T08:00:00.000Z","collectionId":"collection_9f3a2b","collectionName":"Example collection name","showInPlanner":true,"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/vehicles/create-a-vehicle"}}},"/api/v1/vehicles/{vehicleId}":{"delete":{"operationId":"deleteVehicle","tags":["Vehicles"],"summary":"Delete a vehicle","description":"Removes the vehicle from the fleet, together with its declared unavailabilities. It is NOT reversible. Responds 409 if the vehicle has active assignments in orders or future availability rules from a schedule: unassign it, or retire its schedule, first. Responds 204 with no body: the vehicle no longer exists for the API (its GET responds 404).\n\n**Required scope:** `vehicles:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"vehicles:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Vehicle identifier."},"required":true,"description":"Vehicle identifier.","name":"vehicleId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"responses":{"204":{"description":"No content.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/vehicles/delete-a-vehicle"}},"get":{"operationId":"getVehicle","tags":["Vehicles"],"summary":"Get a vehicle","description":"Returns a vehicle by its identifier: license plate, seats, payload, next inspection date, collection and whether it appears in the planner. It does NOT include the cost per kilometer: crossed with the duration of a service it gives what moving the equipment costs the company, and internal costs are excluded from the public edge by design.\n\n**Required scope:** `vehicles:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"vehicles:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Vehicle identifier."},"required":true,"description":"Vehicle identifier.","name":"vehicleId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VehicleResponse"},"example":{"data":{"id":"vehicle_9f3a2b","name":"Example vehicle","status":"active","registrationNumber":"2026-0001","seats":1,"payloadKg":1,"inspectionDate":"2026-09-01T08:00:00.000Z","collectionId":"collection_9f3a2b","collectionName":"Example collection name","showInPlanner":true,"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/vehicles/get-a-vehicle"}},"patch":{"operationId":"updateVehicle","tags":["Vehicles"],"summary":"Update a vehicle","description":"Updates a vehicle (send only the fields to change). It is the endpoint for a fleet integration: operational status, license plate, seats, payload, cargo space dimensions and next inspection date. The cost per kilometer and the fixed cost are NOT part of the public contract. Returns the updated vehicle.\n\n**Required scope:** `vehicles:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"vehicles:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Vehicle identifier."},"required":true,"description":"Vehicle identifier.","name":"vehicleId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VehicleUpdateBody"},"example":{"status":"maintenance","inspectionDate":"2027-03-14T09:00:00+01:00","payloadKg":1200,"dimensions":{"lengthCm":320,"widthCm":175,"heightCm":190,"surfaceAreaM2":5.6}}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VehicleResponse"},"example":{"data":{"id":"vehicle_9f3a2b","name":"Example vehicle","status":"active","registrationNumber":"2026-0001","seats":1,"payloadKg":1,"inspectionDate":"2026-09-01T08:00:00.000Z","collectionId":"collection_9f3a2b","collectionName":"Example collection name","showInPlanner":true,"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/vehicles/update-a-vehicle"}}},"/api/v1/staff":{"get":{"operationId":"listStaff","tags":["Staff"],"summary":"List staff","description":"Returns the staff with the MINIMUM projection needed to plan: who exists, what type they are, whether they drive and whether they appear in the planner. It does NOT include contact, identity, employment, banking or platform access data, and that is deliberate: to write to someone there is the `contacts` resource, with its own scope. Sorted by name.\n\n**Required scope:** `staff:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"staff:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdOn","in":"query"},{"schema":{"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdAfter","in":"query"},{"schema":{"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdBefore","in":"query"},{"schema":{"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdFrom","in":"query"},{"schema":{"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdTo","in":"query"},{"schema":{"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedOn","in":"query"},{"schema":{"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedAfter","in":"query"},{"schema":{"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedBefore","in":"query"},{"schema":{"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedFrom","in":"query"},{"schema":{"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedTo","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":200,"description":"Free-text search on the name."},"required":false,"description":"Free-text search on the name.","name":"q","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, fullName, staffType. Defaults to \"fullName\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, fullName, staffType. Defaults to \"fullName\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["employee","freelancer","contractor"],"description":"Filter by staff member type."},"required":false,"description":"Filter by staff member type.","name":"staffType","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["employee","freelancer","contractor"],"description":"Staff type: employee, self-employed or freelancer."},"minItems":1,"maxItems":50,"description":"Filter by staffType, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by staffType, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"staffTypes","in":"query"},{"schema":{"type":"boolean","description":"Filter by driving licence, useful for assigning transport."},"required":false,"description":"Filter by driving licence, useful for assigning transport.","name":"hasDrivingLicense","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffMemberList"},"example":{"data":[{"id":"staff_member_9f3a2b","fullName":"Example full name","staffType":"employee","collectionId":"collection_9f3a2b","collectionName":"Example collection name","hasDrivingLicense":true,"showInPlanner":true,"externalRef":"Example external ref","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/staff/list-staff"}},"post":{"operationId":"createStaffMember","tags":["Staff"],"summary":"Create a staff member","description":"Registers someone in the staff. The body accepts ONLY the organizational part —name, relationship type, collection, tags and whether they drive—: email, phone and free text are personal data and do not travel through the public edge, just as they are not emitted on read. Returns the created member with the same projection as the listing.\n\n**Required scope:** `staff:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"staff:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffMemberCreateBody"},"example":{"fullName":"Ana Ruiz","staffType":"freelancer","hasDrivingLicense":true,"tags":["Eléctricos","Madrid"]}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffMemberResponse"},"example":{"data":{"id":"staff_member_9f3a2b","fullName":"Example full name","staffType":"employee","collectionId":"collection_9f3a2b","collectionName":"Example collection name","hasDrivingLicense":true,"showInPlanner":true,"externalRef":"Example external ref","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/staff/create-a-staff-member"}}},"/api/v1/staff/{staffId}":{"delete":{"operationId":"deleteStaffMember","tags":["Staff"],"summary":"Delete a staff member","description":"Removes the person from the team, together with their declared unavailabilities. It is NOT reversible. Responds 409 if they have active assignments in orders or future availability rules from a schedule: unassign them, or retire their schedule, first. Responds 204 with no body: the staff member no longer exists for the API (their GET responds 404).\n\n**Required scope:** `staff:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"staff:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Staff member identifier."},"required":true,"description":"Staff member identifier.","name":"staffId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"responses":{"204":{"description":"No content.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/staff/delete-a-staff-member"}},"get":{"operationId":"getStaffMember","tags":["Staff"],"summary":"Get a staff member","description":"Returns a staff member by its identifier. The projection is **the same as the listing**, and that is deliberate: the internal record carries personal and employment data —emergency contact, contract type and hours, internal and external cost, platform role— that is not published to an integrator. This operation exists to resolve an identifier without paginating the whole listing, not to widen what is seen of a person.\n\n**Required scope:** `staff:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"staff:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Staff member identifier."},"required":true,"description":"Staff member identifier.","name":"staffId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffMemberResponse"},"example":{"data":{"id":"staff_member_9f3a2b","fullName":"Example full name","staffType":"employee","collectionId":"collection_9f3a2b","collectionName":"Example collection name","hasDrivingLicense":true,"showInPlanner":true,"externalRef":"Example external ref","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/staff/get-a-staff-member"}},"patch":{"operationId":"updateStaffMember","tags":["Staff"],"summary":"Update a staff member","description":"Updates the ORGANIZATIONAL record of a staff member (send only the fields to change): collection, tags, driving license, visibility in the planner and the external reference used to match them with the record in your system. Identity, contact details and employment terms cannot be written here. Returns the updated member.\n\n**Required scope:** `staff:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"staff:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Staff member identifier."},"required":true,"description":"Staff member identifier.","name":"staffId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffUpdateBody"},"example":{"externalRef":"HR-00412","showInPlanner":true,"hasDrivingLicense":true}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffMemberResponse"},"example":{"data":{"id":"staff_member_9f3a2b","fullName":"Example full name","staffType":"employee","collectionId":"collection_9f3a2b","collectionName":"Example collection name","hasDrivingLicense":true,"showInPlanner":true,"externalRef":"Example external ref","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/staff/update-a-staff-member"}}},"/api/v1/subrents":{"get":{"operationId":"listSubrents","tags":["Subrents"],"summary":"List subrents","description":"Returns the material rented from other companies to cover a job: what was brought in, from whom and for which order. It answers \"of this order, what is mine and what did I have to bring in\". It does not emit what is paid to the supplier.\n\n**Required scope:** `subrents:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"subrents:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdOn","in":"query"},{"schema":{"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdAfter","in":"query"},{"schema":{"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdBefore","in":"query"},{"schema":{"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdFrom","in":"query"},{"schema":{"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdTo","in":"query"},{"schema":{"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedOn","in":"query"},{"schema":{"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedAfter","in":"query"},{"schema":{"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedBefore","in":"query"},{"schema":{"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedFrom","in":"query"},{"schema":{"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedTo","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, startDate, endDate, pickupDate, returnDate, status, type, quantity. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, startDate, endDate, pickupDate, returnDate, status, type, quantity. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["pending","active","completed","cancelled"],"description":"Filter by subrent status."},"required":false,"description":"Filter by subrent status.","name":"status","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["pending","active","completed","cancelled"],"description":"Subrent status: pending, active, completed or cancelled."},"minItems":1,"maxItems":50,"description":"Filter by status, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by status, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"statuses","in":"query"},{"schema":{"type":"string","enum":["bulk","serialized"],"description":"Filter by type: bulk (quantity of a bulk item) or serialized (a specific unit)."},"required":false,"description":"Filter by type: bulk (quantity of a bulk item) or serialized (a specific unit).","name":"type","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["bulk","serialized"],"description":"Subrent type: bulk (by quantity) or serialized (by unit)."},"minItems":1,"maxItems":50,"description":"Filter by type, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by type, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"types","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by the order that motivates it."},"required":false,"description":"Filter by the order that motivates it.","name":"orderId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by orderId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by orderId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"orderIds","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by associated project."},"required":false,"description":"Filter by associated project.","name":"projectId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by projectId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by projectId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"projectIds","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by subrented item."},"required":false,"description":"Filter by subrented item.","name":"itemId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by itemId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by itemId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"itemIds","in":"query"},{"schema":{"description":"The return date to the supplier (returnDate) falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The return date to the supplier (returnDate) falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"returnOn","in":"query"},{"schema":{"description":"The return date to the supplier (returnDate) is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The return date to the supplier (returnDate) is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"returnAfter","in":"query"},{"schema":{"description":"The return date to the supplier (returnDate) is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The return date to the supplier (returnDate) is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"returnBefore","in":"query"},{"schema":{"description":"The return date to the supplier (returnDate) is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The return date to the supplier (returnDate) is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"returnFrom","in":"query"},{"schema":{"description":"The return date to the supplier (returnDate) is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The return date to the supplier (returnDate) is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"returnTo","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubrentList"},"example":{"data":[{"id":"subrent_9f3a2b","type":"bulk","status":"pending","itemId":"item_9f3a2b","itemName":"Example item name","itemSku":"Example item sku","quantity":1,"serializedItemId":"serialized_item_9f3a2b","serializedItemCode":"Example serialized item code","providerId":"provider_9f3a2b","providerName":"Example provider name","needResolved":true,"startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","pickupDate":"2026-09-01T08:00:00.000Z","returnDate":"2026-09-01T08:00:00.000Z","orderId":"order_9f3a2b","projectId":"project_9f3a2b","purchaseOrderId":"purchase_order_9f3a2b","spaceId":"space_9f3a2b","notes":"Example text.","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/subrents/list-subrents"}}},"/api/v1/subrents/{subrentId}":{"get":{"operationId":"getSubrent","tags":["Subrents"],"summary":"Get a subrent","description":"Returns the detail of a subrent by its identifier. Same record as the listing, without what is paid to the supplier.\n\n**Required scope:** `subrents:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"subrents:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Subrent identifier."},"required":true,"description":"Subrent identifier.","name":"subrentId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubrentResponse"},"example":{"data":{"id":"subrent_9f3a2b","type":"bulk","status":"pending","itemId":"item_9f3a2b","itemName":"Example item name","itemSku":"Example item sku","quantity":1,"serializedItemId":"serialized_item_9f3a2b","serializedItemCode":"Example serialized item code","providerId":"provider_9f3a2b","providerName":"Example provider name","needResolved":true,"startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","pickupDate":"2026-09-01T08:00:00.000Z","returnDate":"2026-09-01T08:00:00.000Z","orderId":"order_9f3a2b","projectId":"project_9f3a2b","purchaseOrderId":"purchase_order_9f3a2b","spaceId":"space_9f3a2b","notes":"Example text.","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/subrents/get-a-subrent"}},"patch":{"operationId":"updateSubrent","tags":["Subrents"],"summary":"Update a subrent","description":"Changes the terms of a subrent: status (`pending`, `active`, `completed` or `cancelled`), dates, notes, whether the need is resolved and its link to a purchase order (send only the fields to change). `linkQuantity` deserves attention: if it is LOWER than the quantity of the subrent, the record is SPLIT —the original keeps that quantity and another one is born with the rest—, and what is returned is the original. What is paid to the supplier is NOT part of the public contract, neither to read nor to write. It requires subrents in the plan of the account —included in the current offer, and with the purchases add-on in older plans— (402 without it). Returns the full subrent, the same projection as its GET.\n\n**Required scope:** `subrents:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"subrents:write","x-required-addon":["purchases"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Subrent identifier."},"required":true,"description":"Subrent identifier.","name":"subrentId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubrentUpdateBody"},"example":{"status":"active","purchaseOrderId":"po_00317","needResolved":true,"notes":"Cubierto con la grúa de Alquileres Norte"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubrentResponse"},"example":{"data":{"id":"subrent_9f3a2b","type":"bulk","status":"pending","itemId":"item_9f3a2b","itemName":"Example item name","itemSku":"Example item sku","quantity":1,"serializedItemId":"serialized_item_9f3a2b","serializedItemCode":"Example serialized item code","providerId":"provider_9f3a2b","providerName":"Example provider name","needResolved":true,"startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","pickupDate":"2026-09-01T08:00:00.000Z","returnDate":"2026-09-01T08:00:00.000Z","orderId":"order_9f3a2b","projectId":"project_9f3a2b","purchaseOrderId":"purchase_order_9f3a2b","spaceId":"space_9f3a2b","notes":"Example text.","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/subrents/update-a-subrent"}}},"/api/v1/purchase-orders":{"get":{"operationId":"listPurchaseOrders","tags":["Purchase orders"],"summary":"List purchase orders","description":"Returns what the company buys or subcontracts from its suppliers, with their amounts and their payment status. Amounts are COST amounts, because the object is a purchase. Lines are not published, so the expense cannot be attributed to a specific item of a rental.\n\n**Required scope:** `purchase-orders:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"purchase-orders:read","x-required-addon":["purchases"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdOn","in":"query"},{"schema":{"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdAfter","in":"query"},{"schema":{"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdBefore","in":"query"},{"schema":{"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdFrom","in":"query"},{"schema":{"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdTo","in":"query"},{"schema":{"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedOn","in":"query"},{"schema":{"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedAfter","in":"query"},{"schema":{"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedBefore","in":"query"},{"schema":{"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedFrom","in":"query"},{"schema":{"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedTo","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, poNumber, poDate, status, type, grossPrice, netPrice, isDraft. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, poNumber, poDate, status, type, grossPrice, netPrice, isDraft. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["draft","pending","completed","cancelled"],"description":"Filter by purchase order status."},"required":false,"description":"Filter by purchase order status.","name":"status","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["draft","pending","completed","cancelled"]},"minItems":1,"maxItems":50,"description":"Filter by status, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by status, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"statuses","in":"query"},{"schema":{"type":"string","enum":["subrental","stock_purchase","resale_purchase","consumable_purchase","technician","transport","repair","consignment"],"description":"Filter by purchase order type."},"required":false,"description":"Filter by purchase order type.","name":"type","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["subrental","stock_purchase","resale_purchase","consumable_purchase","technician","transport","repair","consignment"]},"minItems":1,"maxItems":50,"description":"Filter by type, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by type, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"types","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by supplier."},"required":false,"description":"Filter by supplier.","name":"supplierId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by supplierId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by supplierId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"supplierIds","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by associated rental order."},"required":false,"description":"Filter by associated rental order.","name":"orderId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by orderId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by orderId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"orderIds","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by associated project."},"required":false,"description":"Filter by associated project.","name":"projectId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by projectId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by projectId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"projectIds","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseOrderList"},"example":{"data":[{"id":"purchase_order_9f3a2b","poNumber":"2026-0001","status":"draft","type":"subrental","isDraft":true,"poDate":"2026-09-01T08:00:00.000Z","supplierId":"supplier_9f3a2b","reference":"2026-0001","currency":"EUR","subTotal":"120.00","discountTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","totalPaid":"120.00","orderId":"order_9f3a2b","orderNumber":"2026-0001","projectId":"project_9f3a2b","repairTicketId":"repair_ticket_9f3a2b","notes":"Example text.","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/purchase-orders/list-purchase-orders"}}},"/api/v1/purchase-orders/{purchaseOrderId}":{"get":{"operationId":"getPurchaseOrder","tags":["Purchase orders"],"summary":"Get a purchase order","description":"Returns the detail of a purchase order by its identifier.\n\n**Required scope:** `purchase-orders:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"purchase-orders:read","x-required-addon":["purchases"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Purchase order identifier."},"required":true,"description":"Purchase order identifier.","name":"purchaseOrderId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseOrderResponse"},"example":{"data":{"id":"purchase_order_9f3a2b","poNumber":"2026-0001","status":"draft","type":"subrental","isDraft":true,"poDate":"2026-09-01T08:00:00.000Z","supplierId":"supplier_9f3a2b","reference":"2026-0001","currency":"EUR","subTotal":"120.00","discountTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","totalPaid":"120.00","orderId":"order_9f3a2b","orderNumber":"2026-0001","projectId":"project_9f3a2b","repairTicketId":"repair_ticket_9f3a2b","notes":"Example text.","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/purchase-orders/get-a-purchase-order"}},"patch":{"operationId":"updatePurchaseOrder","tags":["Purchase orders"],"summary":"Update a purchase order","description":"Changes the header of a purchase order. `type` always goes, even if it does not change: the approval flow and the numbering series depend on it. LINES are not touched from here, because they are not published; the server calculates the totals from them. The supplier snapshot, the numbering series and the custom fields are left out of the public body. It requires the purchases add-on (402 without it); a consignment purchase order —the stored `type` or the one you send is `consignment`— also requires the consignments add-on, and without it the response is 402 with `requiredAddon: consignments` and nothing is written. A cancelled purchase order, or one locked in the app, cannot be edited: 409 `conflict` and nothing is written. Returns the full purchase order, the same projection as its GET.\n\n**Required scope:** `purchase-orders:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"purchase-orders:write","x-required-addon":["purchases"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Purchase order identifier."},"required":true,"description":"Purchase order identifier.","name":"purchaseOrderId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseOrderUpdateBody"},"example":{"type":"stock_purchase","supplierId":"cont_proveedor_01","poDate":"2026-09-01T00:00:00+02:00","supplierQuoteRef":"PRE-2026-118","reference":"Reposición de trípodes"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseOrderResponse"},"example":{"data":{"id":"purchase_order_9f3a2b","poNumber":"2026-0001","status":"draft","type":"subrental","isDraft":true,"poDate":"2026-09-01T08:00:00.000Z","supplierId":"supplier_9f3a2b","reference":"2026-0001","currency":"EUR","subTotal":"120.00","discountTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","totalPaid":"120.00","orderId":"order_9f3a2b","orderNumber":"2026-0001","projectId":"project_9f3a2b","repairTicketId":"repair_ticket_9f3a2b","notes":"Example text.","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/purchase-orders/update-a-purchase-order"}}},"/api/v1/contracts":{"get":{"operationId":"listContracts","tags":["Contracts"],"summary":"List contracts","description":"Returns the rental contracts with their double status: `status` is the document status (draft, issued, voided) and `operativeStatus` the signature status. `signed` is what decides whether the material can go out. It does not include the legal clauses.\n\n**Required scope:** `contracts:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"contracts:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdOn","in":"query"},{"schema":{"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdAfter","in":"query"},{"schema":{"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdBefore","in":"query"},{"schema":{"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdFrom","in":"query"},{"schema":{"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdTo","in":"query"},{"schema":{"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedOn","in":"query"},{"schema":{"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedAfter","in":"query"},{"schema":{"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedBefore","in":"query"},{"schema":{"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedFrom","in":"query"},{"schema":{"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedTo","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, contractNumber, contractDate, startDate, endDate, status, signedAt, grossPrice. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, contractNumber, contractDate, startDate, endDate, status, signedAt, grossPrice. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["draft","validated","voided"],"description":"Filter by document status: draft, validated (issued) or voided."},"required":false,"description":"Filter by document status: draft, validated (issued) or voided.","name":"status","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["draft","validated","voided"],"description":"Contract document status."},"minItems":1,"maxItems":50,"description":"Filter by status, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by status, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"statuses","in":"query"},{"schema":{"type":"string","enum":["pending","signed","cancelled"],"description":"Filter by signature status: pending, signed or cancelled."},"required":false,"description":"Filter by signature status: pending, signed or cancelled.","name":"operativeStatus","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["pending","signed","cancelled"],"description":"Estado operativo (firma): pending (pendiente de firma), signed (firmado), cancelled (cancelado)."},"minItems":1,"maxItems":50,"description":"Filter by operativeStatus, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by operativeStatus, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"operativeStatuses","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by associated order."},"required":false,"description":"Filter by associated order.","name":"orderId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by orderId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by orderId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"orderIds","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by associated project."},"required":false,"description":"Filter by associated project.","name":"projectId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by projectId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by projectId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"projectIds","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by customer."},"required":false,"description":"Filter by customer.","name":"contactId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by contactId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by contactId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"contactIds","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContractList"},"example":{"data":[{"id":"contract_9f3a2b","contractNumber":"2026-0001","status":"draft","operativeStatus":"pending","signed":true,"signedAt":"2026-09-01T08:00:00.000Z","contactId":"contact_9f3a2b","orderId":"order_9f3a2b","orderNumber":"2026-0001","projectId":"project_9f3a2b","contractDate":"2026-09-01T08:00:00.000Z","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","grossPrice":"120.00","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/contracts/list-contracts"}}},"/api/v1/contracts/{contractId}":{"get":{"operationId":"getContract","tags":["Contracts"],"summary":"Get a contract","description":"Returns the detail of a contract by its identifier.\n\n**Required scope:** `contracts:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"contracts:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Contract identifier."},"required":true,"description":"Contract identifier.","name":"contractId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContractResponse"},"example":{"data":{"id":"contract_9f3a2b","contractNumber":"2026-0001","status":"draft","operativeStatus":"pending","signed":true,"signedAt":"2026-09-01T08:00:00.000Z","contactId":"contact_9f3a2b","orderId":"order_9f3a2b","orderNumber":"2026-0001","projectId":"project_9f3a2b","contractDate":"2026-09-01T08:00:00.000Z","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","grossPrice":"120.00","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/contracts/get-a-contract"}}},"/api/v1/project-types":{"get":{"operationId":"listProjectTypes","tags":["Projects"],"summary":"List project types","description":"Returns the project type catalog of the account. Use it to resolve the `projectTypeId` filter of /api/v1/projects without guessing identifiers. It shares scope with projects, just as task-types does with tasks.\n\n**Required scope:** `projects:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"projects:read","x-rateLimit":{"global":{"perMinute":120}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectTypeItems"},"example":{"data":[{"id":"project_type_9f3a2b","name":"Example project type","color":"Example color","description":"Example text.","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}]}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/projects/list-project-types"}}},"/api/v1/staff/availability":{"post":{"operationId":"checkStaffAvailability","tags":["Staff"],"summary":"Check staff availability","description":"Returns, for each staff member (the whole team, or the ones selected by `staffIds`, `tags`, `collectionId` or `search`), whether they have commitments overlapping the queried window and which ones, typed: order lines, internal services, declared absences and blocking incidents. Unlike /api/v1/availability/check, the response is NOT stock arithmetic: a person has no pool, they are either free or on a specific job. A requested identifier that does not exist comes back as a per-item `error`. Idempotent query (POST because of the structured body). Shares the availability quota of 30 req/min.\n\n**Required scope:** `staff:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"staff:read","x-rateLimit":{"global":{"perMinute":120},"availability":{"perMinute":30}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaffAvailabilityBody"},"example":{"startDate":"2026-09-01T08:00:00Z","endDate":"2026-09-03T20:00:00Z","staffIds":["stf_ana","stf_luis"]}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceAvailabilityEntryItems"},"example":{"data":[{"resourceId":"resource_9f3a2b","name":"Example resource availability entry","available":true,"commitments":[{"kind":"order","orderId":"order_9f3a2b","orderNumber":"2026-0001","label":"Main","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z"}]}]}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/staff/check-staff-availability"}}},"/api/v1/vehicles/availability":{"post":{"operationId":"checkVehicleAvailability","tags":["Vehicles"],"summary":"Check fleet availability","description":"Returns, for each vehicle (the whole fleet, or the ones selected by `vehicleIds`, `tags`, `collectionId` or `search`), whether it has commitments overlapping the queried window and which ones, typed. Same response shape as staff availability. A requested identifier that does not exist comes back as a per-item `error`. Idempotent query (POST because of the structured body). Shares the availability quota of 30 req/min.\n\n**Required scope:** `vehicles:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"vehicles:read","x-rateLimit":{"global":{"perMinute":120},"availability":{"perMinute":30}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VehicleAvailabilityBody"},"example":{"startDate":"2026-09-01T08:00:00Z","endDate":"2026-09-03T20:00:00Z","tags":["tag_furgonetas"]}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceAvailabilityEntryItems"},"example":{"data":[{"resourceId":"resource_9f3a2b","name":"Example resource availability entry","available":true,"commitments":[{"kind":"order","orderId":"order_9f3a2b","orderNumber":"2026-0001","label":"Main","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z"}]}]}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/vehicles/check-fleet-availability"}}},"/api/v1/custom-fields":{"get":{"operationId":"listCustomFields","tags":["Custom fields"],"summary":"List custom field definitions","description":"Returns the custom field DEFINITIONS of the account: which identifier each one has, which type it admits and, if it is a dropdown, which values it accepts. It lets you identify a custom field and the values it accepts. v1 only reads custom fields: no create or update body takes them, so they are set in the Filmo application. It does not return the value assigned to any entity: values travel inside each resource.\n\n**Required scope:** `custom-fields:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"custom-fields:read","x-required-addon":["custom-fields"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","enum":["order","item","space","contact","project","kit","orderTemplate","repairTicket","serializedItem","vehicle","staff","service","purchaseOrder","incident","opportunity","document","all"],"description":"Filter by the entity the field applies to: returns only the definitions usable on that resource type."},"required":false,"description":"Filter by the entity the field applies to: returns only the definitions usable on that resource type.","name":"applyAt","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldDefinitionItems"},"example":{"data":[{"id":"custom_field_definition_9f3a2b","name":"Example custom field definition","dataType":"text","description":"Example text.","options":["Example options"],"applyAt":["order"],"showOn":["quote"],"isActive":true,"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}]}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/custom-fields/list-custom-field-definitions"}}},"/api/v1/tags":{"get":{"operationId":"listTags","tags":["Tags"],"summary":"List tags","description":"Returns the tag vocabulary of the account with how many entities use each one. Resolve the real names before filtering by them.\n\n**Required scope:** `tags:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"tags:read","x-rateLimit":{"global":{"perMinute":120}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagItems"},"example":{"data":[{"id":"tag_9f3a2b","name":"Example tag","count":1,"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}]}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/tags/list-tags"}},"post":{"operationId":"createTag","tags":["Tags"],"summary":"Create a tag","description":"Creates a tag in the vocabulary of the account. If you also send `entityId` and `entityType`, it creates it AND assigns it to that entity in the same step, which is the normal case of an import. The two fields go together or not at all.\n\n**Required scope:** `tags:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"tags:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagCreateBody"},"example":{"name":"Prioritario","entityType":"project","entityId":"prj_00421"}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagCreateResultResponse"},"example":{"data":{"id":"tag_create_result_9f3a2b","name":"Example tag create result","assigned":true}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/tags/create-a-tag"}}},"/api/v1/tags/{tagId}":{"delete":{"operationId":"deleteTag","tags":["Tags"],"summary":"Delete a tag","description":"Deletes the tag from the vocabulary of the account and removes it from every entity that carried it. This is NOT the same as `DELETE /api/v1/tags/{tagId}/assignments`, which unlinks the tag from ONE entity and keeps it. It is NOT reversible. Responds 204 with no body: the tag no longer exists for the API (it disappears from `GET /api/v1/tags`). 404 if the tag does not exist in the account.\n\n**Required scope:** `tags:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"tags:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Tag identifier."},"required":true,"description":"Tag identifier.","name":"tagId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"}],"responses":{"204":{"description":"No content.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/tags/delete-a-tag"}}},"/api/v1/tags/{tagId}/assignments":{"post":{"operationId":"assignTag","tags":["Tags"],"summary":"Assign a tag to an entity","description":"Attaches an existing tag to an entity of the account. The tag goes in the path and the entity in the body.\n\n**Required scope:** `tags:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"tags:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Tag identifier."},"required":true,"description":"Tag identifier.","name":"tagId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagAssignmentBody"},"example":{"entityType":"item","entityId":"itm_9f3a2b"}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagAssignmentResultResponse"},"example":{"data":{"tagId":"tag_9f3a2b","entityId":"entity_9f3a2b","assigned":true}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/tags/assign-a-tag-to-an-entity"}},"delete":{"operationId":"removeTagAssignment","tags":["Tags"],"summary":"Remove a tag from an entity","description":"Undoes the link between a tag and an entity. It does NOT delete the tag from the vocabulary of the account: it still exists and remains assigned to everything else.\n\n**Required scope:** `tags:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"tags:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Tag identifier."},"required":true,"description":"Tag identifier.","name":"tagId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagAssignmentBody"},"example":{"entityType":"item","entityId":"itm_9f3a2b"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagAssignmentResultResponse"},"example":{"data":{"tagId":"tag_9f3a2b","entityId":"entity_9f3a2b","assigned":true}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/tags/remove-a-tag-from-an-entity"}}},"/api/v1/kits":{"get":{"operationId":"listKits","tags":["Kits"],"summary":"List kits","description":"Returns the kits of the catalogue, cursor-paginated: named groups of items that go out together, with their components, collection and tags. Filter by collection and by tag (any of the given tags). Sorted by name; `sort` accepts a single field. Creation and update date filters are not available on this listing.\n\n**Required scope:** `kits:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"kits:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: a single field, with a leading \"-\" for descending (e.g. \"-updatedAt\"). Sortable fields: name, createdAt, updatedAt. Defaults to \"name\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: a single field, with a leading \"-\" for descending (e.g. \"-updatedAt\"). Sortable fields: name, createdAt, updatedAt. Defaults to \"name\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by identifier of the collection the kit belongs to."},"required":false,"description":"Filter by identifier of the collection the kit belongs to.","name":"collectionId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by collectionId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by collectionId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"collectionIds","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by tag identifier: kits that carry that tag."},"required":false,"description":"Filter by tag identifier: kits that carry that tag.","name":"tagId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by tagId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by tagId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"tagIds","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KitList"},"example":{"data":[{"id":"kit_9f3a2b","name":"Example kit","description":"Example text.","image":"Example image","collectionId":"collection_9f3a2b","collectionName":"Example collection name","tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"components":[{"itemId":"item_9f3a2b","itemName":"Example item name","variantId":"variant_9f3a2b","variantName":"Example variant name","quantity":1,"position":1}],"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/kits/list-kits"}},"post":{"operationId":"createKit","tags":["Kits"],"summary":"Create a kit","description":"Registers a named grouping of items that go out together. Tags go by NAME and one that does not exist is created, unlike `POST /api/v1/tags/{tagId}/assignments`, which asks for an identifier. Returns the created kit.\n\n**Required scope:** `kits:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"kits:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KitCreateBody"},"example":{"name":"Kit de iluminación básico","description":"Dos paneles LED, trípodes y difusores.","tags":["Iluminación","Rodaje"]}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KitResponse"},"example":{"data":{"id":"kit_9f3a2b","name":"Example kit","description":"Example text.","image":"Example image","collectionId":"collection_9f3a2b","collectionName":"Example collection name","tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"components":[{"itemId":"item_9f3a2b","itemName":"Example item name","variantId":"variant_9f3a2b","variantName":"Example variant name","quantity":1,"position":1}],"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/kits/create-a-kit"}}},"/api/v1/kits/{kitId}":{"get":{"operationId":"getKit","tags":["Kits"],"summary":"Get a kit","description":"Returns a kit by its identifier: name, description, image, collection and tags. It does NOT return the items that compose it — the internal read does not guarantee them, and publishing a field that is sometimes missing is worse than not publishing it.\n\n**Required scope:** `kits:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"kits:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Kit identifier."},"required":true,"description":"Kit identifier.","name":"kitId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KitResponse"},"example":{"data":{"id":"kit_9f3a2b","name":"Example kit","description":"Example text.","image":"Example image","collectionId":"collection_9f3a2b","collectionName":"Example collection name","tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"components":[{"itemId":"item_9f3a2b","itemName":"Example item name","variantId":"variant_9f3a2b","variantName":"Example variant name","quantity":1,"position":1}],"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/kits/get-a-kit"}},"patch":{"operationId":"updateKit","tags":["Kits"],"summary":"Update a kit","description":"Updates a kit (send only the fields to change). `tags` replaces the whole list. Returns the updated kit.\n\n**Required scope:** `kits:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"kits:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Kit identifier."},"required":true,"description":"Kit identifier.","name":"kitId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KitUpdateBody"},"example":{"name":"Kit de iluminación básico (v2)","description":"Dos paneles LED bicolor, trípodes y difusores."}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KitResponse"},"example":{"data":{"id":"kit_9f3a2b","name":"Example kit","description":"Example text.","image":"Example image","collectionId":"collection_9f3a2b","collectionName":"Example collection name","tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"components":[{"itemId":"item_9f3a2b","itemName":"Example item name","variantId":"variant_9f3a2b","variantName":"Example variant name","quantity":1,"position":1}],"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/kits/update-a-kit"}}},"/api/v1/collections":{"get":{"operationId":"listCollections","tags":["Collections"],"summary":"List collections","description":"Returns the tree the catalog is organized by as a FLAT list: every node with its `parentId`, its full `path` and its `depth`, so the tree is rebuilt in one pass. Filter by what the collections group (`entityType`) or by parent collection. Sorted by path.\n\n**Required scope:** `collections:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"collections:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdOn","in":"query"},{"schema":{"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdAfter","in":"query"},{"schema":{"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdBefore","in":"query"},{"schema":{"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdFrom","in":"query"},{"schema":{"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdTo","in":"query"},{"schema":{"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedOn","in":"query"},{"schema":{"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedAfter","in":"query"},{"schema":{"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedBefore","in":"query"},{"schema":{"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedFrom","in":"query"},{"schema":{"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedTo","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: path, name, order, depth, itemCount, createdAt, updatedAt. Defaults to \"path\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: path, name, order, depth, itemCount, createdAt, updatedAt. Defaults to \"path\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["item","space","vehicle","staff","service"],"description":"Filter by what the collections group: item, space, vehicle, staff or service."},"required":false,"description":"Filter by what the collections group: item, space, vehicle, staff or service.","name":"entityType","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["item","space","vehicle","staff","service"],"description":"What the collection groups."},"minItems":1,"maxItems":50,"description":"Filter by entityType, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by entityType, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"entityTypes","in":"query"},{"schema":{"type":"string","minLength":1,"description":"Filter by parent collection: only its direct children are returned."},"required":false,"description":"Filter by parent collection: only its direct children are returned.","name":"parentId","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionList"},"example":{"data":[{"id":"collection_9f3a2b","name":"Example collection","path":"Example path","entityType":"item","parentId":"parent_9f3a2b","depth":1,"order":1,"itemCount":1,"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/collections/list-collections"}},"post":{"operationId":"createCollection","tags":["Collections"],"summary":"Create a collection","description":"Creates a node of the tree the catalog is organized by. `entityType` decides what the tree is of (items by default) and CANNOT be changed afterwards. Omit `parentCollectionId` for a top-level collection.\n\n**Required scope:** `collections:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"collections:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionCreateBody"},"example":{"name":"Cámaras","description":"Cuerpos de cámara y accesorios de cuerpo.","entityType":"item"}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionCreatedResponse"},"example":{"data":{"id":"collection_created_9f3a2b","name":"Example collection created","entityType":"item"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/collections/create-a-collection"}}},"/api/v1/collections/{collectionId}":{"patch":{"operationId":"updateCollection","tags":["Collections"],"summary":"Update a collection","description":"Renames a collection, moves it to another parent or changes its order. `entityType` is not there: changing it is not supported. A `parentCollectionId` that does not exist or belongs to another account, that is the collection itself or one of its subcollections, or that groups a different type of resource responds 400 `validation_error` with `errors[0].path` on that field; the system collections cannot be modified (409 `conflict`). In both cases nothing is written. Returns the confirmation, not the record, because this resource does not publish a read.\n\n**Required scope:** `collections:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"collections:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Collection identifier."},"required":true,"description":"Collection identifier.","name":"collectionId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionUpdateBody"},"example":{"name":"Cámaras de cine","order":2}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionUpdateResultResponse"},"example":{"data":{"id":"collection_update_result_9f3a2b","updated":true}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/collections/update-a-collection"}}},"/api/v1/services":{"get":{"operationId":"listServices","tags":["Services"],"summary":"List services","description":"Returns the sellable services of the catalogue, cursor-paginated: personnel, transport and work days that do not come from inventory, with their requirements and tags. Filter by type, collection and a single tag. Sorted by name; `sort` accepts a single field. Costs and the internal name are not published; creation and update date filters are not available on this listing.\n\n**Required scope:** `services:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"services:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: a single field, with a leading \"-\" for descending (e.g. \"-updatedAt\"). Sortable fields: name, serviceType, defaultQty, createdAt, updatedAt. Defaults to \"name\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: a single field, with a leading \"-\" for descending (e.g. \"-updatedAt\"). Sortable fields: name, serviceType, defaultQty, createdAt, updatedAt. Defaults to \"name\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["crew","fleet","general"],"description":"Filter by type: crew (personnel), fleet (vehicles) or general."},"required":false,"description":"Filter by type: crew (personnel), fleet (vehicles) or general.","name":"serviceType","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by identifier of the collection the service belongs to."},"required":false,"description":"Filter by identifier of the collection the service belongs to.","name":"collectionId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by collectionId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by collectionId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"collectionIds","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by tag identifier: services that carry that tag."},"required":false,"description":"Filter by tag identifier: services that carry that tag.","name":"tagId","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceList"},"example":{"data":[{"id":"service_9f3a2b","name":"Example service","serviceType":"Example service type","description":"Example text.","defaultQty":1,"showInPlanner":true,"includeInPrice":true,"collectionName":"Example collection name","tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"requirements":[{"requiredResourceType":"personnel","qty":1,"requiredTags":["Example required tags"]}],"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/services/list-services"}},"post":{"operationId":"createService","tags":["Services"],"summary":"Create a service","description":"Registers a sellable line that does not come out of the inventory: a technician, a transport, a working day. The rate is NOT set here — that is what the patch is for, which has its own block. Returns the created service.\n\n**Required scope:** `services:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"services:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceCreateBody"},"example":{"name":"Técnico de iluminación","serviceType":"crew","description":"Jornada de técnico con carné de conducir.","defaultQty":1,"showInPlanner":true,"requirements":[{"requiredResourceType":"personnel","qty":1,"requiredTags":["Eléctricos"]}]}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceResponse"},"example":{"data":{"id":"service_9f3a2b","name":"Example service","serviceType":"Example service type","description":"Example text.","defaultQty":1,"showInPlanner":true,"includeInPrice":true,"collectionName":"Example collection name","tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"requirements":[{"requiredResourceType":"personnel","qty":1,"requiredTags":["Example required tags"]}],"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/services/create-a-service"}}},"/api/v1/services/{serviceId}":{"get":{"operationId":"getService","tags":["Services"],"summary":"Get a service","description":"Returns a sellable service by its identifier: type, default quantity, whether it is included in the document price and which resources are needed to provide it. It does NOT emit its cost or the internal name.\n\n**Required scope:** `services:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"services:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Service identifier."},"required":true,"description":"Service identifier.","name":"serviceId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceResponse"},"example":{"data":{"id":"service_9f3a2b","name":"Example service","serviceType":"Example service type","description":"Example text.","defaultQty":1,"showInPlanner":true,"includeInPrice":true,"collectionName":"Example collection name","tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"requirements":[{"requiredResourceType":"personnel","qty":1,"requiredTags":["Example required tags"]}],"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/services/get-a-service"}},"patch":{"operationId":"updateService","tags":["Services"],"summary":"Update a service","description":"Updates a service (send only the fields to change). It includes the rate, the travel times and the expenses passed on by default —of which only the PRICE goes in, not the cost—. Lists replace the existing one. Returns the updated service.\n\n**Required scope:** `services:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"services:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Service identifier."},"required":true,"description":"Service identifier.","name":"serviceId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceUpdateBody"},"example":{"priceConfig":{"hourlyRate":45,"perKmRate":0.42},"breakMinutes":30,"travelTimeBefore":60,"travelTimeAfter":60,"defaultExpenses":{"catering":{"price":18},"travel":{"price":25}}}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceResponse"},"example":{"data":{"id":"service_9f3a2b","name":"Example service","serviceType":"Example service type","description":"Example text.","defaultQty":1,"showInPlanner":true,"includeInPrice":true,"collectionName":"Example collection name","tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"requirements":[{"requiredResourceType":"personnel","qty":1,"requiredTags":["Example required tags"]}],"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/services/update-a-service"}}},"/api/v1/internal-services":{"get":{"operationId":"listInternalServices","tags":["Internal services"],"summary":"List internal services","description":"Returns the plannable assignments not attached to an order, cursor-paginated. Filter by status, type, project and an overlap window (`overlapsFrom`/`overlapsTo`: assignments whose period overlaps it). Sorted by start date. Creation and update date filters and filtering by assigned resource are not available on this listing.\n\n**Required scope:** `internal-services:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"internal-services:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: startDate, endDate, title, status, createdAt, updatedAt. Defaults to \"startDate\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: startDate, endDate, title, status, createdAt, updatedAt. Defaults to \"startDate\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["active","completed","cancelled"],"description":"Filter by status: active, completed or cancelled."},"required":false,"description":"Filter by status: active, completed or cancelled.","name":"status","in":"query"},{"schema":{"type":"string","enum":["crew","fleet","general"],"description":"Filter by type: crew (personnel), fleet (vehicles) or general."},"required":false,"description":"Filter by type: crew (personnel), fleet (vehicles) or general.","name":"serviceType","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by associated project."},"required":false,"description":"Filter by associated project.","name":"projectId","in":"query"},{"schema":{"description":"Start of the overlap window: returns assignments whose period overlaps [overlapsFrom, overlapsTo]. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"Start of the overlap window: returns assignments whose period overlaps [overlapsFrom, overlapsTo]. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"overlapsFrom","in":"query"},{"schema":{"description":"End of the overlap window: returns assignments whose period overlaps [overlapsFrom, overlapsTo]. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"End of the overlap window: returns assignments whose period overlaps [overlapsFrom, overlapsTo]. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"overlapsTo","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServiceList"},"example":{"data":[{"id":"internal_service_9f3a2b","title":"Example title","status":"Example status","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","projectId":"project_9f3a2b","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/internal-services/list-internal-services"}},"post":{"operationId":"createInternalService","tags":["Internal services"],"summary":"Create an internal service","description":"Schedules a working day that does not hang off an order: maintenance, transfer between warehouses, training. The MINIMUM duration is fifteen minutes. Returns the created internal service.\n\n**Required scope:** `internal-services:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"internal-services:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServiceCreateBody"},"example":{"title":"Mantenimiento de la flota","serviceType":"fleet","startDate":"2026-09-14T08:00:00+02:00","endDate":"2026-09-14T14:00:00+02:00","assignedVehicleIds":["veh_sprinter_1"],"qty":1}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServiceResponse"},"example":{"data":{"id":"internal_service_9f3a2b","title":"Example title","status":"Example status","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","projectId":"project_9f3a2b","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/internal-services/create-an-internal-service"}}},"/api/v1/internal-services/{internalServiceId}":{"get":{"operationId":"getInternalService","tags":["Internal services"],"summary":"Get an internal service","description":"Returns a scheduled internal service that does not hang off an order: its title, its window and the project it is charged to.\n\n**Required scope:** `internal-services:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"internal-services:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Internal service identifier."},"required":true,"description":"Internal service identifier.","name":"internalServiceId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServiceResponse"},"example":{"data":{"id":"internal_service_9f3a2b","title":"Example title","status":"Example status","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","projectId":"project_9f3a2b","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/internal-services/get-an-internal-service"}},"patch":{"operationId":"updateInternalService","tags":["Internal services"],"summary":"Update an internal service","description":"Reschedules or closes an internal service (send only the fields to change). The staff and vehicle lists replace the existing one. Returns the updated internal service.\n\n**Required scope:** `internal-services:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"internal-services:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Internal service identifier."},"required":true,"description":"Internal service identifier.","name":"internalServiceId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServiceUpdateBody"},"example":{"status":"completed","endDate":"2026-09-14T12:30:00+02:00"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalServiceResponse"},"example":{"data":{"id":"internal_service_9f3a2b","title":"Example title","status":"Example status","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","projectId":"project_9f3a2b","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/internal-services/update-an-internal-service"}}},"/api/v1/planner/services":{"get":{"operationId":"listPlannerServices","tags":["Planner"],"summary":"List the services to cover","description":"Returns the staff and fleet services of a date window, with who covers them and which resources are needed. It returns ROWS, not services: each service comes as one `summary` row (`rowKind: summary`, with `staffMemberId` and `vehicleId` always null) and one `detail` row per person or vehicle assigned to it, all sharing the same `orderServiceId`. Group by `orderServiceId`: a service is uncovered when it only has its `summary` row, and covered when it has `detail` rows with an assignee, so a null on the summary row does not mean \"uncovered\". Internal services (not tied to an order) come with `orderId` and `orderNumber` empty and a `serviceId` that starts with `is_`. The identifier used to assign is `orderServiceId`.\n\n**Required scope:** `planner:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"planner:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","format":"date-time","description":"Window start, in ISO 8601 with offset."},"required":true,"description":"Window start, in ISO 8601 with offset.","name":"startDate","in":"query"},{"schema":{"type":"string","format":"date-time","description":"Window end, in ISO 8601 with offset."},"required":true,"description":"Window end, in ISO 8601 with offset.","name":"endDate","in":"query"},{"schema":{"type":"string","enum":["crew","fleet","both"],"description":"Which services to fetch. Defaults to both."},"required":false,"description":"Which services to fetch. Defaults to both.","name":"serviceType","in":"query"},{"schema":{"type":"string","enum":["draft","reserved","all"],"description":"Filter by status of the order they are attached to."},"required":false,"description":"Filter by status of the order they are attached to.","name":"orderStatus","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Limit to one project."},"required":false,"description":"Limit to one project.","name":"projectId","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlannerServiceItems"},"example":{"data":[{"orderServiceId":"order_service_9f3a2b","rowKind":"summary","orderId":"order_9f3a2b","orderNumber":"2026-0001","orderStatus":"Example order status","contactName":"Example contact name","projectId":"project_9f3a2b","projectName":"Example project name","serviceId":"service_9f3a2b","serviceName":"Example service name","serviceType":"Example service type","staffMemberId":"staff_member_9f3a2b","vehicleId":"vehicle_9f3a2b","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","status":"Example status","qty":1,"taskId":"task_9f3a2b","requirements":[{"requiredResourceType":"personnel","qty":1}]}]}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/planner/list-the-services-to-cover"}}},"/api/v1/planner/assignments":{"post":{"operationId":"assignPlannerResource","tags":["Planner"],"summary":"Assign a resource to a service","description":"Puts a person or a vehicle on a service. The target is EXACTLY one: the pair `orderId` + `orderServiceId`, or a task, or an internal service. The resource, also exactly one. `conflictCount` says how many commitments of the resource overlap with this assignment: the assignment is made anyway, and you decide what to do with the number. It responds 400 `validation_error`, with `errors[].path` on the field, when `staffId`, `vehicleId` or the target (`orderServiceId`, `taskId`, `internalServiceId`) does not exist or belongs to another account, when the target does not accept that type of resource (a task only accepts staff; a service, the resource types its requirements declare) and when the task does not block availability; 409 `conflict` when the resource is already assigned to that target or is unavailable in that period. Nothing is written in any of those cases.\n\n**Required scope:** `planner:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"planner:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlannerAssignmentCreateBody"},"example":{"orderId":"ord_0000421","orderServiceId":"osv_0000912","staffId":"stf_luis_perez","role":"Conductor"}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlannerAssignResultResponse"},"example":{"data":{"status":"Example status","conflictCount":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/planner/assign-a-resource-to-a-service"}}},"/api/v1/planner/assignments/remove":{"post":{"operationId":"unassignPlannerResource","tags":["Planner"],"summary":"Remove a resource from a service","description":"Undoes an assignment. It is a POST to a sub-resource and not a DELETE because the target is identified with up to four fields and the resource with three (`assignmentId`, `staffId` or `vehicleId`): that does not fit in a path, and a DELETE with a required body is a worse contract. On a task the resource is always `staffId`: a task has neither vehicles nor assignment identifiers, and sending one of those responds 400 `validation_error` on that field. A target that does not exist or belongs to another account also responds 400 `validation_error`, with `errors[].path` on its field; a resource that is not assigned to that target responds 404 `not_found`: there is nothing to remove.\n\n**Required scope:** `planner:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"planner:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlannerAssignmentRemoveBody"},"example":{"orderId":"ord_0000421","orderServiceId":"osv_0000912","staffId":"stf_luis_perez"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlannerUnassignResultResponse"},"example":{"data":{"status":"Example status"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/planner/remove-a-resource-from-a-service"}}},"/api/v1/schedule":{"get":{"operationId":"getSchedule","tags":["Schedule"],"summary":"Get the schedule for a range","description":"Returns the consolidated schedule of a window: projects, orders, tasks, internal services and order services. It does not paginate: it is bounded by dates, which is what a calendar asks for, but each layer is capped and the response does not say when it was cut: at most 200 projects, 200 orders and 500 tasks, ordered by start date, so a layer that returns exactly its cap may be truncated (use a shorter window). Only active records appear: projects in `draft`, `budgeted`, `confirmed` or `in_progress`, and orders in `draft`, `reserved`, `prepared_partially`, `prepared`, `picked_up_partially`, `picked_up`, `returned_partially`, `returned` or `checked_in_partially`; a `checked_in`, cancelled or archived order is not returned. It is therefore not a complete snapshot: do not delete a record only because it is missing. Assignees come out by identifier and name; their contact details do not.\n\n**Required scope:** `schedule:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"schedule:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","format":"date-time","description":"Window start, in ISO 8601 with offset."},"required":true,"description":"Window start, in ISO 8601 with offset.","name":"startDate","in":"query"},{"schema":{"type":"string","format":"date-time","description":"Window end, in ISO 8601 with offset."},"required":true,"description":"Window end, in ISO 8601 with offset.","name":"endDate","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["projects","orders","tasks","internal_services","order_services"]},"minItems":1,"maxItems":50,"description":"Which layers to fetch: projects, orders, tasks, internal_services or order_services. By default, everything. Repeat the parameter or separate the values with commas for several."},"required":false,"description":"Which layers to fetch: projects, orders, tasks, internal_services or order_services. By default, everything. Repeat the parameter or separate the values with commas for several.","name":"layers","in":"query"},{"schema":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":50,"description":"Filter projects by status."},"required":false,"description":"Filter projects by status.","name":"projectStatus","in":"query"},{"schema":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":50,"description":"Filter orders by status."},"required":false,"description":"Filter orders by status.","name":"orderStatus","in":"query"},{"schema":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":200,"description":"Keep only what is assigned to these staff members."},"required":false,"description":"Keep only what is assigned to these staff members.","name":"assignedToStaffIds","in":"query"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleResponse"},"example":{"data":{"projects":[{"id":"project_9f3a2b","name":"Example project","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","status":"Example status"}],"orders":[{"id":"order_9f3a2b","orderNumber":"2026-0001","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","status":"Example status","contactName":"Example contact name","projectName":"Example project name"}],"tasks":[{"id":"task_9f3a2b","title":"Example title","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","isAllDay":true,"isCompleted":true,"type":"Example type","projectId":"project_9f3a2b","assignedStaff":[{"id":"assigned_staff_9f3a2b","fullName":"Example full name"}]}],"internalServices":[{"id":"internal_service_9f3a2b","title":"Example title","serviceType":"Example service type","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","projectName":"Example project name","qty":1,"assignedStaff":[{"id":"assigned_staff_9f3a2b","fullName":"Example full name"}],"assignedVehicleIds":["assigned_vehicle_9f3a2b"]}],"orderServices":[{"orderId":"order_9f3a2b","orderNumber":"2026-0001","serviceName":"Example service name","serviceType":"Example service type","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","contactName":"Example contact name","projectName":"Example project name","qty":1,"assignedCount":1,"assignedStaff":[{"id":"assigned_staff_9f3a2b","fullName":"Example full name"}]}]}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/schedule/get-the-schedule-for-a-range"}}},"/api/v1/availability/unavailabilities":{"get":{"operationId":"listUnavailabilities","tags":["Availability"],"summary":"List the unavailabilities of a resource","description":"Returns the windows in which a person, a vehicle or a space is NOT available. `absenceType` is emitted for vehicles and spaces, where it is operational, and NOT for people, where it would be health data. The reason for the unavailability is never emitted. Only declarations with `state: unavailable` that have not ended yet (current or future) are returned: an unavailability disappears from the list once its end date has passed, and `available` or `unknown` windows are never listed.\n\n**Required scope:** `availability:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"availability:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","enum":["staff","vehicle","space"],"description":"Which resources to query."},"required":true,"description":"Which resources to query.","name":"resourceType","in":"query"},{"schema":{"type":"string","minLength":1,"description":"Limit to a specific resource."},"required":false,"description":"Limit to a specific resource.","name":"resourceId","in":"query"},{"schema":{"type":"string","format":"date-time","description":"Start of the window, in ISO 8601 with offset."},"required":false,"description":"Start of the window, in ISO 8601 with offset.","name":"startDate","in":"query"},{"schema":{"type":"string","format":"date-time","description":"End of the window, in ISO 8601 with offset."},"required":false,"description":"End of the window, in ISO 8601 with offset.","name":"endDate","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnavailabilityList"},"example":{"data":[{"id":"unavailability_9f3a2b","resourceType":"Example resource type","resourceId":"resource_9f3a2b","resourceName":"Example resource name","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","state":"Madrid","absenceType":"Example absence type","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/availability/list-the-unavailabilities-of-a-resource"}},"post":{"operationId":"createUnavailability","tags":["Availability"],"summary":"Declare an unavailability","description":"Declares that a resource is not available in a window: holidays, a maintenance, a closure. `reason` is ACCEPTED and not returned: it stays in Filmo for whoever has access. For a person or a vehicle, overlapping commitments do not block: the unavailability is recorded and `warningCount` says how many already reserved commitments overlap with it. A space is different: declaring it `unavailable` in a window where it is booked responds 409 `conflict` and nothing is written, so on a space `warningCount` is always 0. It also responds 409 if an identical unavailability already exists (same resource, window, state, type and reason). It responds 400 `validation_error`, with `errors[0].path` on the field, when `endDate` is not after `startDate`, when `resourceId` does not exist or belongs to another account, and when `absenceType` is not one of its resource type: `vacation`, `sick`, `personal`, `training` or `other` for staff; `maintenance`, `inspection`, `repair`, `reserved` or `other` for vehicles; `academic`, `maintenance`, `event`, `closure` or `other` for spaces. On a space it responds 503 `service_unavailable` while space unavailabilities are switched off for the account.\n\n**Required scope:** `availability:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"availability:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnavailabilityCreateBody"},"example":{"resourceType":"staff","resourceId":"stf_ana","startDate":"2026-08-01T00:00:00+02:00","endDate":"2026-08-15T23:59:59+02:00","state":"unavailable","absenceType":"vacation"}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnavailabilityResultResponse"},"example":{"data":{"availability":{"id":"availability_9f3a2b","resourceType":"Example resource type","resourceId":"resource_9f3a2b","resourceName":"Example resource name","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","state":"Madrid","absenceType":"Example absence type","updatedAt":"2026-09-01T08:00:00.000Z"},"warningCount":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}},"503":{"description":"Service unavailable (service_unavailable): the feature this operation writes to is switched off for the account. The request is correct; it works again once the feature is switched on.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"service_unavailable":{"$ref":"#/components/examples/Problem_service_unavailable"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/availability/declare-an-unavailability"}}},"/api/v1/availability/unavailabilities/{unavailabilityId}":{"delete":{"operationId":"deleteUnavailability","tags":["Availability"],"summary":"Delete an unavailability","description":"Deletes a manual unavailability that has not started yet. It is NOT reversible. Only manual, future ones can be deleted: responds 409 if it is managed by a task or by a schedule (remove it from its source) or if it has already started (close it with `finish_now` through its PATCH instead). Responds 204 with no body. Unavailabilities have no detail GET, so `If-Match` is not supported on this operation. On a space it responds 503 `service_unavailable` while space unavailabilities are switched off for the account.\n\n**Required scope:** `availability:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"availability:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Unavailability identifier."},"required":true,"description":"Unavailability identifier.","name":"unavailabilityId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"}],"responses":{"204":{"description":"No content.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}},"503":{"description":"Service unavailable (service_unavailable): the feature this operation writes to is switched off for the account. The request is correct; it works again once the feature is switched on.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"service_unavailable":{"$ref":"#/components/examples/Problem_service_unavailable"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/availability/delete-an-unavailability"}},"patch":{"operationId":"updateUnavailability","tags":["Availability"],"summary":"Correct or close an unavailability","description":"With `action: \"edit\"` it corrects the dates or the type; with `action: \"finish_now\"` it closes it at this instant, which is the \"came back early\" case. `expectedUpdatedAt` is the optimistic lock: copy it from the read and, if someone touched it in the meantime, the request is rejected with 409 `conflict` and nothing is written; read it again and retry. `edit` only applies to a manual unavailability that has not started yet: one created by a task or by a schedule is changed from its source, and one already started can only be closed; both respond 409. Its new start has to be later than now and its end after its start (400 `validation_error` with `errors[0].path` on the field, as with an `absenceType` of another resource type), and on a space the new window cannot fall on its bookings (409). `finish_now` only closes an unavailability in progress —`unavailable`, already started and not yet ended—, also one that comes from a schedule; any other responds 409, and so does one created by a task. `warningCount` is always 0 here: overlapping commitments are counted when the unavailability is declared. On a space it responds 503 `service_unavailable` while space unavailabilities are switched off for the account.\n\n**Required scope:** `availability:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"availability:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Unavailability identifier."},"required":true,"description":"Unavailability identifier.","name":"unavailabilityId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnavailabilityUpdateBody"},"example":{"action":"finish_now","expectedUpdatedAt":"2026-07-20T10:12:31+02:00"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnavailabilityResultResponse"},"example":{"data":{"availability":{"id":"availability_9f3a2b","resourceType":"Example resource type","resourceId":"resource_9f3a2b","resourceName":"Example resource name","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","state":"Madrid","absenceType":"Example absence type","updatedAt":"2026-09-01T08:00:00.000Z"},"warningCount":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}},"503":{"description":"Service unavailable (service_unavailable): the feature this operation writes to is switched off for the account. The request is correct; it works again once the feature is switched on.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"service_unavailable":{"$ref":"#/components/examples/Problem_service_unavailable"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/availability/correct-or-close-an-unavailability"}}},"/api/v1/incidents":{"get":{"operationId":"listIncidents","tags":["Incidents"],"summary":"List incidents","description":"Returns the incidents of the account, cursor-paginated: broken, lost or malfunctioning material with its repair status. Filter by status, nature, scope, priority, severity, availability impact, affected resource, order, project, assignee, creation date and target resolution date. Sorted by creation date, newest first; `sort` accepts a single field. Repair costs, resolution notes and whether the cost is charged to the client are not published. Behind the `incidence` add-on: without it, 402.\n\n**Required scope:** `incidents:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"incidents:read","x-required-addon":["incidence"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"description":"The creation date of the incident falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the incident falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdOn","in":"query"},{"schema":{"description":"The creation date of the incident is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the incident is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdAfter","in":"query"},{"schema":{"description":"The creation date of the incident is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the incident is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdBefore","in":"query"},{"schema":{"description":"The creation date of the incident is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the incident is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdFrom","in":"query"},{"schema":{"description":"The creation date of the incident is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the incident is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdTo","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: a single field, with a leading \"-\" for descending (e.g. \"-updatedAt\"). Sortable fields: createdAt, updatedAt, dueDate, identifier, title, status, priority. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: a single field, with a leading \"-\" for descending (e.g. \"-updatedAt\"). Sortable fields: createdAt, updatedAt, dueDate, identifier, title, status, priority. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["draft","open","waiting","repairing","complete","lost"],"description":"Filter by lifecycle status: draft, open, waiting, repairing, complete or lost."},"required":false,"description":"Filter by lifecycle status: draft, open, waiting, repairing, complete or lost.","name":"status","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["draft","open","waiting","repairing","complete","lost"],"description":"Lifecycle status: draft, open, waiting, repairing, complete or lost."},"minItems":1,"maxItems":50,"description":"Filter by status, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by status, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"statuses","in":"query"},{"schema":{"type":"string","enum":["damage","loss","malfunction","cosmetic","theft","custom"],"description":"Filter by nature: damage, loss, malfunction, cosmetic, theft or custom."},"required":false,"description":"Filter by nature: damage, loss, malfunction, cosmetic, theft or custom.","name":"type","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["damage","loss","malfunction","cosmetic","theft","custom"],"description":"Nature: damage, loss, malfunction, cosmetic, theft or custom."},"minItems":1,"maxItems":50,"description":"Filter by type, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by type, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"types","in":"query"},{"schema":{"type":"string","enum":["item","serializedItem","space","kit","vehicle","custom"],"description":"Filter by what it affects: item, serializedItem, space, kit, vehicle or custom."},"required":false,"description":"Filter by what it affects: item, serializedItem, space, kit, vehicle or custom.","name":"scope","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["item","serializedItem","space","kit","vehicle","custom"],"description":"What it affects: item, serializedItem, space, kit, vehicle or custom."},"minItems":1,"maxItems":50,"description":"Filter by scope, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by scope, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"scopes","in":"query"},{"schema":{"type":"string","enum":["urgent","high","medium","low","none"],"description":"Filter by priority: urgent, high, medium, low or none."},"required":false,"description":"Filter by priority: urgent, high, medium, low or none.","name":"priority","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["urgent","high","medium","low","none"],"description":"Priority: urgent, high, medium, low or none."},"minItems":1,"maxItems":50,"description":"Filter by priority, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by priority, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"priorities","in":"query"},{"schema":{"type":"string","enum":["low","high","blocking"],"description":"Filter by severity: low, high or blocking."},"required":false,"description":"Filter by severity: low, high or blocking.","name":"severity","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["low","high","blocking"],"description":"Severity: low, high or blocking."},"minItems":1,"maxItems":50,"description":"Filter by severity, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by severity, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"severities","in":"query"},{"schema":{"type":"boolean","description":"Filter by availability impact: \"true\" only incidents that remove the material from the available pool, \"false\" only those that do not. Omit it to apply no filter."},"required":false,"description":"Filter by availability impact: \"true\" only incidents that remove the material from the available pool, \"false\" only those that do not. Omit it to apply no filter.","name":"blocksAvailability","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by affected item."},"required":false,"description":"Filter by affected item.","name":"itemId","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by affected physical unit."},"required":false,"description":"Filter by affected physical unit.","name":"serializedItemId","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by affected space."},"required":false,"description":"Filter by affected space.","name":"spaceId","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by affected vehicle."},"required":false,"description":"Filter by affected vehicle.","name":"vehicleId","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by the order in which it was detected."},"required":false,"description":"Filter by the order in which it was detected.","name":"orderId","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by associated project."},"required":false,"description":"Filter by associated project.","name":"projectId","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by assigned staff member (the same identifier that assigneeStaffIds takes when writing)."},"required":false,"description":"Filter by assigned staff member (the same identifier that assigneeStaffIds takes when writing).","name":"assigneeStaffId","in":"query"},{"schema":{"description":"The target resolution date of the incident falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The target resolution date of the incident falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"dueOn","in":"query"},{"schema":{"description":"The target resolution date of the incident is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The target resolution date of the incident is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"dueAfter","in":"query"},{"schema":{"description":"The target resolution date of the incident is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The target resolution date of the incident is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"dueBefore","in":"query"},{"schema":{"description":"The target resolution date of the incident is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The target resolution date of the incident is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"dueFrom","in":"query"},{"schema":{"description":"The target resolution date of the incident is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The target resolution date of the incident is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"dueTo","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentList"},"example":{"data":[{"id":"incident_9f3a2b","identifier":"Example identifier","title":"Example title","description":"Example text.","type":"Example type","scope":"item","status":"Example status","priority":"Example priority","severity":"Example severity","blocksAvailability":true,"affectedQuantity":1,"itemId":"item_9f3a2b","serializedItemId":"serialized_item_9f3a2b","spaceId":"space_9f3a2b","vehicleId":"vehicle_9f3a2b","orderId":"order_9f3a2b","projectId":"project_9f3a2b","dueDate":"2026-09-01T08:00:00.000Z","commentCount":1,"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/incidents/list-incidents"}},"post":{"operationId":"createIncident","tags":["Incidents"],"summary":"Open an incident","description":"Records broken, lost or damaged material. With `blocksAvailability: true` the material leaves the available pool while the incident remains open; if the item is tracked by quantity and you do not indicate a specific physical unit, `affectedQuantity` becomes required. The repair cost is NOT part of the public contract. Returns the created incident.\n\n**Required scope:** `incidents:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"incidents:write","x-required-addon":["incidence"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentCreateBody"},"example":{"title":"Montura dañada en la devolución","type":"damage","scope":"serializedItem","priority":"high","blocksAvailability":true,"itemId":"itm_9f3a2b","serializedItemId":"ser_00187","orderId":"ord_00421","description":"La montura llega con holgura; no sujeta el objetivo.","dueDate":"2026-09-20T12:00:00+02:00"}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"},"example":{"data":{"id":"incident_9f3a2b","identifier":"Example identifier","title":"Example title","description":"Example text.","type":"Example type","scope":"item","status":"Example status","priority":"Example priority","severity":"Example severity","blocksAvailability":true,"affectedQuantity":1,"itemId":"item_9f3a2b","serializedItemId":"serialized_item_9f3a2b","spaceId":"space_9f3a2b","vehicleId":"vehicle_9f3a2b","orderId":"order_9f3a2b","projectId":"project_9f3a2b","dueDate":"2026-09-01T08:00:00.000Z","commentCount":1,"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/incidents/open-an-incident"}}},"/api/v1/incidents/{incidentId}":{"get":{"operationId":"getIncident","tags":["Incidents"],"summary":"Get an incident","description":"Returns an incident by its identifier: what broke, what it falls on, which status it is in and whether it blocks the availability of the material. It does NOT include the repair cost or the internal resolution note.\n\n**Required scope:** `incidents:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"incidents:read","x-required-addon":["incidence"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Incident identifier."},"required":true,"description":"Incident identifier.","name":"incidentId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"},"example":{"data":{"id":"incident_9f3a2b","identifier":"Example identifier","title":"Example title","description":"Example text.","type":"Example type","scope":"item","status":"Example status","priority":"Example priority","severity":"Example severity","blocksAvailability":true,"affectedQuantity":1,"itemId":"item_9f3a2b","serializedItemId":"serialized_item_9f3a2b","spaceId":"space_9f3a2b","vehicleId":"vehicle_9f3a2b","orderId":"order_9f3a2b","projectId":"project_9f3a2b","dueDate":"2026-09-01T08:00:00.000Z","commentCount":1,"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/incidents/get-an-incident"}},"patch":{"operationId":"updateIncident","tags":["Incidents"],"summary":"Update an incident","description":"Updates an incident (send only the fields to change). Lists fully replace the existing one. Costs, the internal resolution note and publication on the customer portal cannot be written here. Returns the updated incident.\n\n**Required scope:** `incidents:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"incidents:write","x-required-addon":["incidence"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Incident identifier."},"required":true,"description":"Incident identifier.","name":"incidentId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentUpdateBody"},"example":{"status":"repairing","repairType":"external","estimatedResolutionDate":"2026-09-25T12:00:00+02:00"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"},"example":{"data":{"id":"incident_9f3a2b","identifier":"Example identifier","title":"Example title","description":"Example text.","type":"Example type","scope":"item","status":"Example status","priority":"Example priority","severity":"Example severity","blocksAvailability":true,"affectedQuantity":1,"itemId":"item_9f3a2b","serializedItemId":"serialized_item_9f3a2b","spaceId":"space_9f3a2b","vehicleId":"vehicle_9f3a2b","orderId":"order_9f3a2b","projectId":"project_9f3a2b","dueDate":"2026-09-01T08:00:00.000Z","commentCount":1,"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/incidents/update-an-incident"}}},"/api/v1/incidents/status-counts":{"get":{"operationId":"getIncidentStatusCounts","tags":["Incidents"],"summary":"Count incidents by status","description":"Returns how many incidents there are in each status, with optional filters by project, space, vehicle, item, physical unit or order. The six keys always come out, with 0 if there are none. It is the only way to discover the volume: this resource does not publish a listing.\n\n**Required scope:** `incidents:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"incidents:read","x-required-addon":["incidence"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by project."},"required":false,"description":"Filter by project.","name":"projectId","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by space."},"required":false,"description":"Filter by space.","name":"spaceId","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by vehicle."},"required":false,"description":"Filter by vehicle.","name":"vehicleId","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by catalog item."},"required":false,"description":"Filter by catalog item.","name":"itemId","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by physical unit."},"required":false,"description":"Filter by physical unit.","name":"serializedItemId","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by order."},"required":false,"description":"Filter by order.","name":"orderId","in":"query"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentStatusCountsResponse"},"example":{"data":{"draft":1,"open":1,"waiting":1,"repairing":1,"complete":1,"lost":1}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/incidents/count-incidents-by-status"}}},"/api/v1/incidents/{incidentId}/comments":{"post":{"operationId":"addIncidentComment","tags":["Incidents"],"summary":"Comment on an incident","description":"Records progress on the incident: the workshop confirming receipt, the quote arriving. It does not accept attachments because v1 has no file upload. Returns the full incident, with its `commentCount` updated, the same projection as its GET.\n\n**Required scope:** `incidents:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"incidents:write","x-required-addon":["incidence"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Incident identifier."},"required":true,"description":"Incident identifier.","name":"incidentId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentCommentBody"},"example":{"text":"El taller confirma recepción. Presupuesto en 48 h."}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"},"example":{"data":{"id":"incident_9f3a2b","identifier":"Example identifier","title":"Example title","description":"Example text.","type":"Example type","scope":"item","status":"Example status","priority":"Example priority","severity":"Example severity","blocksAvailability":true,"affectedQuantity":1,"itemId":"item_9f3a2b","serializedItemId":"serialized_item_9f3a2b","spaceId":"space_9f3a2b","vehicleId":"vehicle_9f3a2b","orderId":"order_9f3a2b","projectId":"project_9f3a2b","dueDate":"2026-09-01T08:00:00.000Z","commentCount":1,"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/incidents/comment-on-an-incident"}}},"/api/v1/notes":{"get":{"operationId":"listNotes","tags":["Notes"],"summary":"List the notes of an entity","description":"Returns the notes attached to ONE entity of the account, newest first. `relatedDocumentType` and `relatedDocumentId` are required — there is no listing of all the notes — and the entity must belong to the account: otherwise it responds 404 without reading anything.\n\n**Required scope:** `notes:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"notes:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdOn","in":"query"},{"schema":{"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdAfter","in":"query"},{"schema":{"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdBefore","in":"query"},{"schema":{"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdFrom","in":"query"},{"schema":{"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdTo","in":"query"},{"schema":{"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedOn","in":"query"},{"schema":{"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedAfter","in":"query"},{"schema":{"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedBefore","in":"query"},{"schema":{"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedFrom","in":"query"},{"schema":{"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedTo","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["item","contact","order","space","kit","vehicle","staff","service","collection","project","repairTicket","purchaseOrder","supplierInvoice"],"description":"Type of the entity whose notes are listed. Required."},"required":true,"description":"Type of the entity whose notes are listed. Required.","name":"relatedDocumentType","in":"query"},{"schema":{"type":"string","minLength":1,"description":"Identifier of that entity. Required; it must belong to the account."},"required":true,"description":"Identifier of that entity. Required; it must belong to the account.","name":"relatedDocumentId","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteList"},"example":{"data":[{"id":"note_9f3a2b","content":"Example content","relatedDocumentType":"Example related document type","relatedDocumentId":"related_document_9f3a2b","subRelatedDocumentType":"Example sub related document type","subRelatedDocumentId":"sub_related_document_9f3a2b","subRelatedDocumentCode":"Example sub related document code","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/notes/list-the-notes-of-an-entity"}},"post":{"operationId":"createNote","tags":["Notes"],"summary":"Write a note on an entity","description":"Leaves a record on an entity of the account: why an order was rejected, how a repair is going. With `subRelatedDocumentType` and `subRelatedDocumentId` the note goes on a specific physical unit and not on the whole item. `mentionedUserIds` notifies those Filmo users. The notes of an entity are read with `GET /api/v1/notes`.\n\n**Required scope:** `notes:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"notes:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteCreateBody"},"example":{"relatedDocumentType":"item","relatedDocumentId":"itm_9f3a2b","subRelatedDocumentType":"serializedItem","subRelatedDocumentId":"ser_00187","subRelatedDocumentCode":"FX6-01","content":"Revisada la montura tras el rodaje; sin holgura."}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteResponse"},"example":{"data":{"id":"note_9f3a2b","content":"Example content","relatedDocumentType":"Example related document type","relatedDocumentId":"related_document_9f3a2b","subRelatedDocumentType":"Example sub related document type","subRelatedDocumentId":"sub_related_document_9f3a2b","subRelatedDocumentCode":"Example sub related document code","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/notes/write-a-note-on-an-entity"}}},"/api/v1/tasks":{"get":{"operationId":"listTasks","tags":["Tasks"],"summary":"List tasks","description":"Returns the tasks and schedule events, cursor-paginated. Strict per-subscription tenancy.\n\n**Required scope:** `tasks:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"tasks:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdOn","in":"query"},{"schema":{"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdAfter","in":"query"},{"schema":{"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdBefore","in":"query"},{"schema":{"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdFrom","in":"query"},{"schema":{"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdTo","in":"query"},{"schema":{"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedOn","in":"query"},{"schema":{"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedAfter","in":"query"},{"schema":{"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedBefore","in":"query"},{"schema":{"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedFrom","in":"query"},{"schema":{"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedTo","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, startDate, endDate, title, isCompleted, type. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, startDate, endDate, title, isCompleted, type. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","format":"date-time","description":"Start of the overlap window (ISO 8601 with offset): returns tasks that overlap [from, to] (a task that starts before and ends within counts)."},"required":false,"description":"Start of the overlap window (ISO 8601 with offset): returns tasks that overlap [from, to] (a task that starts before and ends within counts).","name":"from","in":"query"},{"schema":{"type":"string","format":"date-time","description":"End of the overlap window (ISO 8601 with offset): returns tasks that overlap [from, to]."},"required":false,"description":"End of the overlap window (ISO 8601 with offset): returns tasks that overlap [from, to].","name":"to","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by assigned staff member (the same identifier that assignedStaffIds exposes in the DTO)."},"required":false,"description":"Filter by assigned staff member (the same identifier that assignedStaffIds exposes in the DTO).","name":"assignedStaffId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by assignedStaffId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by assignedStaffId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"assignedStaffIds","in":"query"},{"schema":{"type":"boolean","description":"Filter by completion: \"true\" only completed tasks, \"false\" only pending tasks. Omit it to apply no filter."},"required":false,"description":"Filter by completion: \"true\" only completed tasks, \"false\" only pending tasks. Omit it to apply no filter.","name":"isCompleted","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by task type: its identifier (system types: default, delivery, return, temporaryStock; custom types: their id) or its name, matched ignoring case and accents. A name that matches no type yields an empty list; one that matches several is rejected with 400."},"required":false,"description":"Filter by task type: its identifier (system types: default, delivery, return, temporaryStock; custom types: their id) or its name, matched ignoring case and accents. A name that matches no type yields an empty list; one that matches several is rejected with 400.","name":"type","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by type, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by type, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"types","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by identifier of the document related to the task."},"required":false,"description":"Filter by identifier of the document related to the task.","name":"relatedDocumentId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by relatedDocumentId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by relatedDocumentId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"relatedDocumentIds","in":"query"},{"schema":{"description":"The task due date (its end or, if it has none, its start) falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The task due date (its end or, if it has none, its start) falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"dueOn","in":"query"},{"schema":{"description":"The task due date (its end or, if it has none, its start) is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The task due date (its end or, if it has none, its start) is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"dueAfter","in":"query"},{"schema":{"description":"The task due date (its end or, if it has none, its start) is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The task due date (its end or, if it has none, its start) is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"dueBefore","in":"query"},{"schema":{"description":"The task due date (its end or, if it has none, its start) is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The task due date (its end or, if it has none, its start) is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"dueFrom","in":"query"},{"schema":{"description":"The task due date (its end or, if it has none, its start) is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The task due date (its end or, if it has none, its start) is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"dueTo","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskList"},"example":{"data":[{"id":"task_9f3a2b","title":"Example title","description":"Example text.","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","isAllDay":true,"isCompleted":true,"isRecurring":true,"recurringGroupId":"recurring_group_9f3a2b","recurrencePattern":{"frequency":"daily","interval":1,"endAfterOccurrences":1,"endDate":"2026-09-01T08:00:00.000Z"},"type":"Example type","assignedStaffIds":["assigned_staff_9f3a2b"],"projectId":"project_9f3a2b","relatedDocumentId":"related_document_9f3a2b","relatedDocumentType":"Example related document type","appearance":{"color":"Example color","variant":"primary"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/tasks/list-tasks"}},"post":{"operationId":"createTask","tags":["Tasks"],"summary":"Create a task","description":"Creates a task with domain validation: the type, the staff, the project and the related document are checked against your account, and a foreign reference responds 400 without creating anything. Returns the created task.\n\n**Required scope:** `tasks:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"tasks:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskCreateBody"},"example":{"title":"Preparar kit de iluminación para rodaje","description":"Revisar baterías y focos antes de la entrega.","startDate":"2026-09-01T09:00:00+02:00","endDate":"2026-09-01T11:00:00+02:00","isAllDay":false,"type":"default","assignedStaffIds":["stf_ana","stf_luis"],"projectId":"prj_rodaje_otono","relatedDocumentId":"ord_00421","relatedDocumentType":"order"}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskResponse"},"example":{"data":{"id":"task_9f3a2b","title":"Example title","description":"Example text.","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","isAllDay":true,"isCompleted":true,"isRecurring":true,"recurringGroupId":"recurring_group_9f3a2b","recurrencePattern":{"frequency":"daily","interval":1,"endAfterOccurrences":1,"endDate":"2026-09-01T08:00:00.000Z"},"type":"Example type","assignedStaffIds":["assigned_staff_9f3a2b"],"projectId":"project_9f3a2b","relatedDocumentId":"related_document_9f3a2b","relatedDocumentType":"Example related document type","appearance":{"color":"Example color","variant":"primary"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/tasks/create-a-task"}}},"/api/v1/tasks/{taskId}":{"get":{"operationId":"getTask","tags":["Tasks"],"summary":"Get a task","description":"Returns the detail of a task by its identifier.\n\n**Required scope:** `tasks:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"tasks:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Task identifier."},"required":true,"description":"Task identifier.","name":"taskId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskResponse"},"example":{"data":{"id":"task_9f3a2b","title":"Example title","description":"Example text.","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","isAllDay":true,"isCompleted":true,"isRecurring":true,"recurringGroupId":"recurring_group_9f3a2b","recurrencePattern":{"frequency":"daily","interval":1,"endAfterOccurrences":1,"endDate":"2026-09-01T08:00:00.000Z"},"type":"Example type","assignedStaffIds":["assigned_staff_9f3a2b"],"projectId":"project_9f3a2b","relatedDocumentId":"related_document_9f3a2b","relatedDocumentType":"Example related document type","appearance":{"color":"Example color","variant":"primary"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/tasks/get-a-task"}},"delete":{"operationId":"deleteTask","tags":["Tasks"],"summary":"Delete a task","description":"Deletes the task from the schedule, together with its staff assignments and its mirror on the external calendar, if any. It is NOT reversible. The delivery and return tasks that a reservation creates are deleted by cancelling the order, not here. Responds 204 with no body: the task no longer exists for the API (its GET responds 404). 404 if the task does not exist or belongs to another account.\n\n**Required scope:** `tasks:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"tasks:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Task identifier."},"required":true,"description":"Task identifier.","name":"taskId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"responses":{"204":{"description":"No content.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/tasks/delete-a-task"}},"patch":{"operationId":"updateTask","tags":["Tasks"],"summary":"Update a task","description":"Partially updates a task (send only the fields to change). The staff, the project and the related document are checked against your account just as on creation. Returns the updated task.\n\n**Required scope:** `tasks:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"tasks:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Task identifier."},"required":true,"description":"Task identifier.","name":"taskId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskUpdateBody"},"example":{"isCompleted":true,"assignedStaffIds":["stf_ana"]}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskResponse"},"example":{"data":{"id":"task_9f3a2b","title":"Example title","description":"Example text.","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","isAllDay":true,"isCompleted":true,"isRecurring":true,"recurringGroupId":"recurring_group_9f3a2b","recurrencePattern":{"frequency":"daily","interval":1,"endAfterOccurrences":1,"endDate":"2026-09-01T08:00:00.000Z"},"type":"Example type","assignedStaffIds":["assigned_staff_9f3a2b"],"projectId":"project_9f3a2b","relatedDocumentId":"related_document_9f3a2b","relatedDocumentType":"Example related document type","appearance":{"color":"Example color","variant":"primary"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/tasks/update-a-task"}}},"/api/v1/task-types":{"get":{"operationId":"listTaskTypes","tags":["Task types"],"summary":"List task types","description":"Returns the task type catalog: system ones first and then the custom ones of the account. No pagination.\n\n**Required scope:** `tasks:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"tasks:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"boolean","default":false,"description":"Include archived types: \"true\" returns them in addition to the active ones; \"false\" or omission hides them."},"required":false,"description":"Include archived types: \"true\" returns them in addition to the active ones; \"false\" or omission hides them.","name":"includeArchived","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskTypeItems"},"example":{"data":[{"id":"task_type_9f3a2b","name":"Example task type","color":"Example color","isSystem":true,"isArchived":true,"tasksCount":1,"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}]}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/task-types/list-task-types"}}},"/api/v1/crm/opportunities":{"get":{"operationId":"listOpportunities","tags":["CRM"],"summary":"List opportunities","description":"Returns the sales opportunities with their pipeline, their stage and their amount weighted by the probability of the stage. By default only the open ones: pass `status=won`, `lost` or `all` for the rest. It paginates by a cursor specific to the CRM service.\n\n**Required scope:** `crm:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"crm:read","x-required-addon":["crm"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, name, identifier, status, amount, expectedCloseDate. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, name, identifier, status, amount, expectedCloseDate. Defaults to \"-createdAt\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","description":"Returns only the opportunities in this pipeline."},"required":false,"description":"Returns only the opportunities in this pipeline.","name":"pipelineId","in":"query"},{"schema":{"type":"string","description":"Returns only the opportunities in this stage."},"required":false,"description":"Returns only the opportunities in this stage.","name":"stageId","in":"query"},{"schema":{"type":"string","enum":["open","won","lost","all"],"description":"Commercial status: open (the default), won, lost or all."},"required":false,"description":"Commercial status: open (the default), won, lost or all.","name":"status","in":"query"},{"schema":{"type":"string","description":"Returns only the opportunities of this contact."},"required":false,"description":"Returns only the opportunities of this contact.","name":"contactId","in":"query"},{"schema":{"type":"string","description":"Free-text search on the name and the identifier."},"required":false,"description":"Free-text search on the name and the identifier.","name":"q","in":"query"},{"schema":{"type":"string","description":"Expected close date from this date (ISO 8601)."},"required":false,"description":"Expected close date from this date (ISO 8601).","name":"expectedCloseFrom","in":"query"},{"schema":{"type":"string","description":"Expected close date up to this date (ISO 8601)."},"required":false,"description":"Expected close date up to this date (ISO 8601).","name":"expectedCloseTo","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpportunityList"},"example":{"data":[{"opportunityId":"opportunity_9f3a2b","identifier":"Example identifier","name":"Example opportunity","status":"open","amount":"120.00","currency":"EUR","pipelineId":"pipeline_9f3a2b","pipelineName":"Example pipeline name","stageId":"stage_9f3a2b","stageName":"Example stage name","stageType":"open","effectiveProbability":1,"weightedAmount":"120.00","daysInStage":1,"expectedCloseDate":"2026-09-01T10:00:00+02:00","contactName":"Example contact name","companyName":"Example company name","ownerName":"Example owner name","source":"inbound_email","createdAt":"2026-09-01T10:00:00+02:00","updatedAt":"2026-09-01T10:00:00+02:00"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/crm/list-opportunities"}},"post":{"operationId":"createOpportunity","tags":["CRM"],"summary":"Create an opportunity","description":"Puts a lead into the pipeline. If you omit `pipelineId` it uses the default pipeline of the account, and if you omit `stageId` the first stage of that pipeline. The amount goes as a decimal string so as not to lose cents to floating-point rounding. Returns the created opportunity with its effective probability and its weighted amount.\n\n**Required scope:** `crm:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"crm:write","x-required-addon":["crm"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpportunityCreateBody"},"example":{"name":"Spot de otoño — Producciones Delta","amount":"12500.00","currency":"EUR","expectedCloseDate":"2026-10-15T00:00:00+02:00","contactId":"cont_8f2a1c","source":"website_form","utmCampaign":"otono-2026"}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpportunityDetailResponse"},"example":{"data":{"opportunityId":"opportunity_9f3a2b","identifier":"Example identifier","name":"Example opportunity","status":"open","amount":"120.00","currency":"EUR","pipelineId":"pipeline_9f3a2b","pipelineName":"Example pipeline name","stageId":"stage_9f3a2b","stageName":"Example stage name","stageType":"open","effectiveProbability":1,"weightedAmount":"120.00","daysInStage":1,"expectedCloseDate":"2026-09-01T10:00:00+02:00","contactName":"Example contact name","companyName":"Example company name","ownerName":"Example owner name","source":"inbound_email","createdAt":"2026-09-01T10:00:00+02:00","updatedAt":"2026-09-01T10:00:00+02:00","description":"Example text.","version":1,"collaboratorStaffIds":["collaborator_staff_9f3a2b"],"quoteIds":["quote_9f3a2b"],"stageHistory":[{"fromStageId":"from_stage_9f3a2b","toStageId":"to_stage_9f3a2b","toStatus":"Example to status","daysInPrevStage":1,"movedAt":"2026-09-01T10:00:00+02:00","note":"Example text."}]}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/crm/create-an-opportunity"}}},"/api/v1/crm/opportunities/{opportunityId}":{"get":{"operationId":"getOpportunity","tags":["CRM"],"summary":"Get an opportunity","description":"Returns the record of an opportunity: the summary plus the description, the collaborators and the linked quotes. With `includeHistory=true` it adds `stageHistory`, the stage moves from most recent to oldest — it is an additional query, so it does not come by default.\n\n**Required scope:** `crm:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"crm:read","x-required-addon":["crm"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Opportunity identifier."},"required":true,"description":"Opportunity identifier.","name":"opportunityId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpportunityDetailResponse"},"example":{"data":{"opportunityId":"opportunity_9f3a2b","identifier":"Example identifier","name":"Example opportunity","status":"open","amount":"120.00","currency":"EUR","pipelineId":"pipeline_9f3a2b","pipelineName":"Example pipeline name","stageId":"stage_9f3a2b","stageName":"Example stage name","stageType":"open","effectiveProbability":1,"weightedAmount":"120.00","daysInStage":1,"expectedCloseDate":"2026-09-01T10:00:00+02:00","contactName":"Example contact name","companyName":"Example company name","ownerName":"Example owner name","source":"inbound_email","createdAt":"2026-09-01T10:00:00+02:00","updatedAt":"2026-09-01T10:00:00+02:00","description":"Example text.","version":1,"collaboratorStaffIds":["collaborator_staff_9f3a2b"],"quoteIds":["quote_9f3a2b"],"stageHistory":[{"fromStageId":"from_stage_9f3a2b","toStageId":"to_stage_9f3a2b","toStatus":"Example to status","daysInPrevStage":1,"movedAt":"2026-09-01T10:00:00+02:00","note":"Example text."}]}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/crm/get-an-opportunity"}},"patch":{"operationId":"updateOpportunity","tags":["CRM"],"summary":"Update an opportunity","description":"Updates an opportunity (send only the fields to change). `version` is REQUIRED: copy it from the previous read. If someone moved it between your read and your write, the request is rejected instead of overwriting their change. To move stage or close, use their own endpoints.\n\n**Required scope:** `crm:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"crm:write","x-required-addon":["crm"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Opportunity identifier."},"required":true,"description":"Opportunity identifier.","name":"opportunityId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpportunityUpdateBody"},"example":{"amount":"13800.00","expectedCloseDate":"2026-10-22T00:00:00+02:00"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpportunityDetailResponse"},"example":{"data":{"opportunityId":"opportunity_9f3a2b","identifier":"Example identifier","name":"Example opportunity","status":"open","amount":"120.00","currency":"EUR","pipelineId":"pipeline_9f3a2b","pipelineName":"Example pipeline name","stageId":"stage_9f3a2b","stageName":"Example stage name","stageType":"open","effectiveProbability":1,"weightedAmount":"120.00","daysInStage":1,"expectedCloseDate":"2026-09-01T10:00:00+02:00","contactName":"Example contact name","companyName":"Example company name","ownerName":"Example owner name","source":"inbound_email","createdAt":"2026-09-01T10:00:00+02:00","updatedAt":"2026-09-01T10:00:00+02:00","description":"Example text.","version":1,"collaboratorStaffIds":["collaborator_staff_9f3a2b"],"quoteIds":["quote_9f3a2b"],"stageHistory":[{"fromStageId":"from_stage_9f3a2b","toStageId":"to_stage_9f3a2b","toStatus":"Example to status","daysInPrevStage":1,"movedAt":"2026-09-01T10:00:00+02:00","note":"Example text."}]}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/crm/update-an-opportunity"}}},"/api/v1/crm/opportunities/{opportunityId}/stage":{"patch":{"operationId":"moveOpportunityStage","tags":["CRM"],"summary":"Move an opportunity to another stage","description":"Moves the opportunity forward or backward within its pipeline. The target stage has to be of open type: for won or lost stages there is the close endpoint. `version` is the same optimistic lock as in the patch.\n\n**Required scope:** `crm:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"crm:write","x-required-addon":["crm"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Opportunity identifier."},"required":true,"description":"Opportunity identifier.","name":"opportunityId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpportunityMoveStageBody"},"example":{"toStageId":"stg_negociacion"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpportunityDetailResponse"},"example":{"data":{"opportunityId":"opportunity_9f3a2b","identifier":"Example identifier","name":"Example opportunity","status":"open","amount":"120.00","currency":"EUR","pipelineId":"pipeline_9f3a2b","pipelineName":"Example pipeline name","stageId":"stage_9f3a2b","stageName":"Example stage name","stageType":"open","effectiveProbability":1,"weightedAmount":"120.00","daysInStage":1,"expectedCloseDate":"2026-09-01T10:00:00+02:00","contactName":"Example contact name","companyName":"Example company name","ownerName":"Example owner name","source":"inbound_email","createdAt":"2026-09-01T10:00:00+02:00","updatedAt":"2026-09-01T10:00:00+02:00","description":"Example text.","version":1,"collaboratorStaffIds":["collaborator_staff_9f3a2b"],"quoteIds":["quote_9f3a2b"],"stageHistory":[{"fromStageId":"from_stage_9f3a2b","toStageId":"to_stage_9f3a2b","toStatus":"Example to status","daysInPrevStage":1,"movedAt":"2026-09-01T10:00:00+02:00","note":"Example text."}]}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/crm/move-an-opportunity-to-another-stage"}}},"/api/v1/crm/opportunities/{opportunityId}/close":{"post":{"operationId":"closeOpportunity","tags":["CRM"],"summary":"Close an opportunity","description":"Closes the opportunity as won or lost. If you omit `toStageId` it goes to the first stage of the corresponding type in the pipeline. When losing, the reason goes STRUCTURED (`lostReason`): it is what makes the pipeline analyzable afterwards.\n\n**Required scope:** `crm:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"crm:write","x-required-addon":["crm"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Opportunity identifier."},"required":true,"description":"Opportunity identifier.","name":"opportunityId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpportunityCloseBody"},"example":{"outcome":"lost","lostReason":"lost_to_competitor"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpportunityDetailResponse"},"example":{"data":{"opportunityId":"opportunity_9f3a2b","identifier":"Example identifier","name":"Example opportunity","status":"open","amount":"120.00","currency":"EUR","pipelineId":"pipeline_9f3a2b","pipelineName":"Example pipeline name","stageId":"stage_9f3a2b","stageName":"Example stage name","stageType":"open","effectiveProbability":1,"weightedAmount":"120.00","daysInStage":1,"expectedCloseDate":"2026-09-01T10:00:00+02:00","contactName":"Example contact name","companyName":"Example company name","ownerName":"Example owner name","source":"inbound_email","createdAt":"2026-09-01T10:00:00+02:00","updatedAt":"2026-09-01T10:00:00+02:00","description":"Example text.","version":1,"collaboratorStaffIds":["collaborator_staff_9f3a2b"],"quoteIds":["quote_9f3a2b"],"stageHistory":[{"fromStageId":"from_stage_9f3a2b","toStageId":"to_stage_9f3a2b","toStatus":"Example to status","daysInPrevStage":1,"movedAt":"2026-09-01T10:00:00+02:00","note":"Example text."}]}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/crm/close-an-opportunity"}}},"/api/v1/crm/opportunities/{opportunityId}/links":{"post":{"operationId":"linkOpportunityRecord","tags":["CRM"],"summary":"Link a document to an opportunity","description":"Ties to the opportunity the quote, the order or the project that came out of it. With `kind: \"quote\"` and `isPrimary: true`, that quote becomes the primary one and the others are demoted. `meta.created` distinguishes a new link from one that already existed, which is what a retry needs to know. Returns the full opportunity, the same projection as its GET. The link itself —`kind`, `linkedEntityId`, `created`— goes in `meta`.\n\n**Required scope:** `crm:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"crm:write","x-required-addon":["crm"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Opportunity identifier."},"required":true,"description":"Opportunity identifier.","name":"opportunityId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpportunityLinkBody"},"example":{"kind":"quote","quoteId":"qte_00312","isPrimary":true}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkOpportunityRecordResponse"},"example":{"data":{"opportunityId":"opportunity_9f3a2b","identifier":"Example identifier","name":"Example opportunity","status":"open","amount":"120.00","currency":"EUR","pipelineId":"pipeline_9f3a2b","pipelineName":"Example pipeline name","stageId":"stage_9f3a2b","stageName":"Example stage name","stageType":"open","effectiveProbability":1,"weightedAmount":"120.00","daysInStage":1,"expectedCloseDate":"2026-09-01T10:00:00+02:00","contactName":"Example contact name","companyName":"Example company name","ownerName":"Example owner name","source":"inbound_email","createdAt":"2026-09-01T10:00:00+02:00","updatedAt":"2026-09-01T10:00:00+02:00","description":"Example text.","version":1,"collaboratorStaffIds":["collaborator_staff_9f3a2b"],"quoteIds":["quote_9f3a2b"],"stageHistory":[{"fromStageId":"from_stage_9f3a2b","toStageId":"to_stage_9f3a2b","toStatus":"Example to status","daysInPrevStage":1,"movedAt":"2026-09-01T10:00:00+02:00","note":"Example text."}]},"meta":{"kind":"Example kind","linkedEntityId":"linked_entity_9f3a2b","created":true}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/crm/link-a-document-to-an-opportunity"}}},"/api/v1/crm/pipelines":{"get":{"operationId":"listPipelines","tags":["CRM"],"summary":"List pipelines","description":"Returns the pipelines of the account with their ordered stages. Use it to resolve `pipelineId` and `stageId` of the opportunities listing without guessing identifiers. It does NOT paginate: an account has a handful of pipelines and all of them are returned.\n\n**Required scope:** `crm:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"crm:read","x-required-addon":["crm"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"boolean","default":false,"description":"If \"true\", archived pipelines are included as well. By default only the active ones are returned."},"required":false,"description":"If \"true\", archived pipelines are included as well. By default only the active ones are returned.","name":"includeArchived","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineItems"},"example":{"data":[{"pipelineId":"pipeline_9f3a2b","name":"Example pipeline","slug":"Example slug","isDefault":true,"isArchived":true,"totalOpportunities":1,"totalValue":"120.00","stages":[{"stageId":"stage_9f3a2b","name":"Example stage","order":1,"type":"open","probability":1,"isDefault":true}],"createdAt":"2026-09-01T10:00:00+02:00","updatedAt":"2026-09-01T10:00:00+02:00"}]}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/crm/list-pipelines"}}},"/api/v1/crm/pipelines/{pipelineId}":{"get":{"operationId":"getPipeline","tags":["CRM"],"summary":"Get a pipeline","description":"Returns a pipeline by its identifier, with its ordered stages and their type (open, won or lost).\n\n**Required scope:** `crm:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"crm:read","x-required-addon":["crm"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Pipeline identifier."},"required":true,"description":"Pipeline identifier.","name":"pipelineId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineResponse"},"example":{"data":{"pipelineId":"pipeline_9f3a2b","name":"Example pipeline","slug":"Example slug","isDefault":true,"isArchived":true,"totalOpportunities":1,"totalValue":"120.00","stages":[{"stageId":"stage_9f3a2b","name":"Example stage","order":1,"type":"open","probability":1,"isDefault":true}],"createdAt":"2026-09-01T10:00:00+02:00","updatedAt":"2026-09-01T10:00:00+02:00"}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/crm/get-a-pipeline"}}},"/api/v1/purchase-orders/{purchaseOrderId}/approve":{"post":{"operationId":"approvePurchaseOrder","tags":["Purchase orders"],"summary":"Approve a purchase order","description":"Approves the order and leaves it in `pending`. It takes no body, and it is a sub-resource and not a patch of `status` because the server checks the order before moving it. Only a draft with a supplier is approved: any other status —an order already approved, too— responds 409 `conflict` naming it, and a draft without supplier responds 409 as well; nothing changes in either case. Returns the full purchase order, the same projection as its GET.\n\n**Required scope:** `purchase-orders:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"purchase-orders:write","x-required-addon":["purchases"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Purchase order identifier."},"required":true,"description":"Purchase order identifier.","name":"purchaseOrderId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseOrderResponse"},"example":{"data":{"id":"purchase_order_9f3a2b","poNumber":"2026-0001","status":"draft","type":"subrental","isDraft":true,"poDate":"2026-09-01T08:00:00.000Z","supplierId":"supplier_9f3a2b","reference":"2026-0001","currency":"EUR","subTotal":"120.00","discountTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","totalPaid":"120.00","orderId":"order_9f3a2b","orderNumber":"2026-0001","projectId":"project_9f3a2b","repairTicketId":"repair_ticket_9f3a2b","notes":"Example text.","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/purchase-orders/approve-a-purchase-order"}}},"/api/v1/purchase-orders/{purchaseOrderId}/receive":{"post":{"operationId":"receivePurchaseOrder","tags":["Purchase orders"],"summary":"Receive material from a purchase order","description":"Declares what arrived and in what quantity, line by line. `newStockReceived` registers NEW inventory, so always send the `Idempotency-Key` header: without it, a retry duplicates the stock. The order may end up partially received. The line identifier is `lineId`. Returns the full purchase order, the same projection as its GET. `meta.receivedLines` says how many lines the call declared as received. A draft or cancelled order responds 409 `conflict`.\n\n**Required scope:** `purchase-orders:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"purchase-orders:write","x-required-addon":["purchases"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Purchase order identifier."},"required":true,"description":"Purchase order identifier.","name":"purchaseOrderId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseOrderReceiveBody"},"example":{"spaceId":"spc_almacen_central","lines":[{"lineId":"pol_00317","receivedQuantity":6,"newStockReceived":4,"notes":"Dos vienen con la caja abierta"}]}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReceivePurchaseOrderResponse"},"example":{"data":{"id":"purchase_order_9f3a2b","poNumber":"2026-0001","status":"draft","type":"subrental","isDraft":true,"poDate":"2026-09-01T08:00:00.000Z","supplierId":"supplier_9f3a2b","reference":"2026-0001","currency":"EUR","subTotal":"120.00","discountTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","totalPaid":"120.00","orderId":"order_9f3a2b","orderNumber":"2026-0001","projectId":"project_9f3a2b","repairTicketId":"repair_ticket_9f3a2b","notes":"Example text.","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"},"meta":{"receivedLines":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/purchase-orders/receive-material-from-a-purchase-order"}}},"/api/v1/supplier-invoices":{"get":{"operationId":"listSupplierInvoices","tags":["Supplier invoices"],"summary":"List supplier invoices","description":"Returns the invoices received from suppliers, cursor-paginated, with the same compact card as the detail read. Filter by status within the purchasing cycle, supplier contact, linked sales order, project, invoice date and due date. Sorted by invoice date, most recent first.\n\n**Required scope:** `supplier-invoices:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"supplier-invoices:read","x-required-addon":["purchases"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdOn","in":"query"},{"schema":{"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdAfter","in":"query"},{"schema":{"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdBefore","in":"query"},{"schema":{"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdFrom","in":"query"},{"schema":{"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdTo","in":"query"},{"schema":{"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedOn","in":"query"},{"schema":{"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedAfter","in":"query"},{"schema":{"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedBefore","in":"query"},{"schema":{"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedFrom","in":"query"},{"schema":{"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedTo","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, invoiceDate, dueDate. Defaults to \"-invoiceDate\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, invoiceDate, dueDate. Defaults to \"-invoiceDate\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["draft","validated","voided"],"description":"Filter by status within the purchasing cycle: draft, validated or voided."},"required":false,"description":"Filter by status within the purchasing cycle: draft, validated or voided.","name":"status","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["draft","validated","voided"],"description":"Status within the purchasing cycle: draft, validated or voided."},"minItems":1,"maxItems":50,"description":"Filter by status, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by status, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"statuses","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by identifier of the supplier contact that issued the invoice."},"required":false,"description":"Filter by identifier of the supplier contact that issued the invoice.","name":"contactId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by contactId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by contactId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"contactIds","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by identifier of the sales order the invoice is linked to."},"required":false,"description":"Filter by identifier of the sales order the invoice is linked to.","name":"orderId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by orderId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by orderId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"orderIds","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by identifier of the project linked to the invoice, directly or through its order."},"required":false,"description":"Filter by identifier of the project linked to the invoice, directly or through its order.","name":"projectId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by projectId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by projectId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"projectIds","in":"query"},{"schema":{"description":"The date the supplier put on the invoice falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The date the supplier put on the invoice falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"invoiceDateOn","in":"query"},{"schema":{"description":"The date the supplier put on the invoice is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The date the supplier put on the invoice is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"invoiceDateAfter","in":"query"},{"schema":{"description":"The date the supplier put on the invoice is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The date the supplier put on the invoice is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"invoiceDateBefore","in":"query"},{"schema":{"description":"The date the supplier put on the invoice is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The date the supplier put on the invoice is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"invoiceDateFrom","in":"query"},{"schema":{"description":"The date the supplier put on the invoice is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The date the supplier put on the invoice is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"invoiceDateTo","in":"query"},{"schema":{"description":"The supplier invoice due date falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The supplier invoice due date falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"dueOn","in":"query"},{"schema":{"description":"The supplier invoice due date is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The supplier invoice due date is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"dueAfter","in":"query"},{"schema":{"description":"The supplier invoice due date is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The supplier invoice due date is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"dueBefore","in":"query"},{"schema":{"description":"The supplier invoice due date is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The supplier invoice due date is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"dueFrom","in":"query"},{"schema":{"description":"The supplier invoice due date is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The supplier invoice due date is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"dueTo","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierInvoiceList"},"example":{"data":[{"id":"supplier_invoice_9f3a2b","supplierInvoiceNumber":"2026-0001","status":"Example status","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/supplier-invoices/list-supplier-invoices"}}},"/api/v1/supplier-invoices/{supplierInvoiceId}":{"get":{"operationId":"getSupplierInvoice","tags":["Supplier invoices"],"summary":"Get a supplier invoice","description":"Returns an invoice received from a supplier by its identifier, the same compact card as `GET /api/v1/supplier-invoices`.\n\n**Required scope:** `supplier-invoices:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"supplier-invoices:read","x-required-addon":["purchases"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Supplier invoice identifier."},"required":true,"description":"Supplier invoice identifier.","name":"supplierInvoiceId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierInvoiceResponse"},"example":{"data":{"id":"supplier_invoice_9f3a2b","supplierInvoiceNumber":"2026-0001","status":"Example status","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/supplier-invoices/get-a-supplier-invoice"}}},"/api/v1/treasury/accounts":{"get":{"operationId":"listTreasuryAccounts","tags":["Treasury"],"summary":"List treasury accounts","description":"Returns the accounts money comes in and goes out through, sorted by name; archived accounts are left out unless requested. The BANK ACCOUNT NUMBER and the balance are not published: the identifier is enough to say which account a payment went through.\n\n**Required scope:** `treasury:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"treasury:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: a single field, with a leading \"-\" for descending (e.g. \"-updatedAt\"). Sortable fields: name, type, status, currency, createdAt, updatedAt. Defaults to \"name\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: a single field, with a leading \"-\" for descending (e.g. \"-updatedAt\"). Sortable fields: name, type, status, currency, createdAt, updatedAt. Defaults to \"name\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["bank","cash","manual"],"description":"Filter by account type: bank (a bank account), cash (a cash box) or manual."},"required":false,"description":"Filter by account type: bank (a bank account), cash (a cash box) or manual.","name":"type","in":"query"},{"schema":{"type":"string","enum":["active","needs_reauth","disconnected","archived"],"description":"Filter by status: active, needs_reauth, disconnected or archived. Without it, archived accounts are left out unless `includeArchived` is true."},"required":false,"description":"Filter by status: active, needs_reauth, disconnected or archived. Without it, archived accounts are left out unless `includeArchived` is true.","name":"status","in":"query"},{"schema":{"type":"string","minLength":3,"maxLength":3,"description":"Filter by currency, as an ISO 4217 code."},"required":false,"description":"Filter by currency, as an ISO 4217 code.","name":"currency","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include archived accounts. Off by default; ignored when `status` is given."},"required":false,"description":"Set it to true to include archived accounts. Off by default; ignored when `status` is given.","name":"includeArchived","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TreasuryAccountList"},"example":{"data":[{"id":"treasury_account_9f3a2b","name":"Example treasury account","type":"bank","currency":"EUR","status":"active","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/treasury/list-treasury-accounts"}}},"/api/v1/treasury/accounts/{accountId}":{"get":{"operationId":"getTreasuryAccount","tags":["Treasury"],"summary":"Get a treasury account","description":"Returns an account by its identifier. The BANK ACCOUNT NUMBER is not published: to say which account a payment came in or went out through, the account identifier is enough. Accounts are not created or modified through this API.\n\n**Required scope:** `treasury:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"treasury:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Treasury account identifier."},"required":true,"description":"Treasury account identifier.","name":"accountId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TreasuryAccountResponse"},"example":{"data":{"id":"treasury_account_9f3a2b","name":"Example treasury account","type":"bank","currency":"EUR","status":"active","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/treasury/get-a-treasury-account"}}},"/api/v1/treasury/payments":{"get":{"operationId":"listPayments","tags":["Treasury"],"summary":"List treasury payments","description":"Returns the collections and payments recorded in treasury, newest first, with the same projection as their GET. Filter by direction, type, treasury account, contact, linked invoice, credit note or order, bank reconciliation and payment date. Notes and the reconciliation state are not published.\n\n**Required scope:** `treasury:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"treasury:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: a single field, with a leading \"-\" for descending (e.g. \"-updatedAt\"). Sortable fields: date, amount, createdAt, updatedAt. Defaults to \"-date\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: a single field, with a leading \"-\" for descending (e.g. \"-updatedAt\"). Sortable fields: date, amount, createdAt, updatedAt. Defaults to \"-date\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["in","out"],"description":"Filter by direction: in (money coming in) or out (money going out)."},"required":false,"description":"Filter by direction: in (money coming in) or out (money going out).","name":"direction","in":"query"},{"schema":{"type":"string","enum":["normal","deposit","transfer"],"description":"Filter by payment type: normal, deposit (an advance payment) or transfer (an internal transfer between treasury accounts)."},"required":false,"description":"Filter by payment type: normal, deposit (an advance payment) or transfer (an internal transfer between treasury accounts).","name":"type","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["normal","deposit","transfer"],"description":"Payment type: normal, deposit (an advance payment) or transfer (an internal transfer between treasury accounts)."},"minItems":1,"maxItems":50,"description":"Filter by type, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by type, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"types","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by the treasury account the payment goes through."},"required":false,"description":"Filter by the treasury account the payment goes through.","name":"treasuryAccountId","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by the customer or supplier of the payment."},"required":false,"description":"Filter by the customer or supplier of the payment.","name":"contactId","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by the invoice the payment is assigned to."},"required":false,"description":"Filter by the invoice the payment is assigned to.","name":"invoiceId","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by the credit note the payment is assigned to."},"required":false,"description":"Filter by the credit note the payment is assigned to.","name":"creditNoteId","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by the order the payment is assigned to."},"required":false,"description":"Filter by the order the payment is assigned to.","name":"orderId","in":"query"},{"schema":{"type":"boolean","description":"Filter by bank reconciliation: true for reconciled payments, false for the ones still pending. Absent means no filter."},"required":false,"description":"Filter by bank reconciliation: true for reconciled payments, false for the ones still pending. Absent means no filter.","name":"reconciled","in":"query"},{"schema":{"description":"The payment date falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The payment date falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"dateOn","in":"query"},{"schema":{"description":"The payment date is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The payment date is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"dateAfter","in":"query"},{"schema":{"description":"The payment date is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The payment date is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"dateBefore","in":"query"},{"schema":{"description":"The payment date is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The payment date is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"dateFrom","in":"query"},{"schema":{"description":"The payment date is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The payment date is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"dateTo","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentList"},"example":{"data":[{"id":"payment_9f3a2b","direction":"Example direction","amount":"120.00","currency":"EUR","date":"2026-09-01T08:00:00.000Z","type":"Example type","treasuryAccountId":"treasury_account_9f3a2b","contactId":"contact_9f3a2b","reference":"2026-0001","linkedDocuments":[{"type":"invoice","id":"linked_document_9f3a2b","amount":"120.00"}],"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/treasury/list-treasury-payments"}},"post":{"operationId":"createPayment","tags":["Treasury"],"summary":"Record an incoming or outgoing payment","description":"Records a payment in a treasury account. The document it is tied to goes as the PAIR `linkedDocumentType` + `linkedDocumentId`, never as one field per type: sending two identifiers at once would leave it unknown which one it was tied to. `type: \"deposit\"` marks a security deposit collected from a customer: it requires `direction: in` (400 on `direction` otherwise) and does not deduct from the order total. The date can be any time of today but not a later day, in the time zone of the account (400 on `date`). Send `Idempotency-Key`: a retry without it records the payment twice. Returns the full payment, the same projection as its GET.\n\n**Required scope:** `treasury:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"treasury:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentCreateBody"},"example":{"direction":"in","amount":"1815.50","currency":"EUR","date":"2026-09-04T12:00:00+02:00","paymentMethodId":"pmt_transferencia","treasuryAccountId":"tac_principal","contactId":"cont_00118","linkedDocumentType":"invoice","linkedDocumentId":"inv_02291","reference":"Transf. 4471-A"}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentResponse"},"example":{"data":{"id":"payment_9f3a2b","direction":"Example direction","amount":"120.00","currency":"EUR","date":"2026-09-01T08:00:00.000Z","type":"Example type","treasuryAccountId":"treasury_account_9f3a2b","contactId":"contact_9f3a2b","reference":"2026-0001","linkedDocuments":[{"type":"invoice","id":"linked_document_9f3a2b","amount":"120.00"}],"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/treasury/record-an-incoming-or-outgoing-payment"}}},"/api/v1/treasury/payments/{paymentId}":{"get":{"operationId":"getPayment","tags":["Treasury"],"summary":"Get a payment","description":"Returns an incoming or outgoing payment by its identifier, the same projection as `GET /api/v1/treasury/payments`. Internal notes and the reconciliation status are not returned.\n\n**Required scope:** `treasury:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"treasury:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Treasury payment identifier."},"required":true,"description":"Treasury payment identifier.","name":"paymentId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentResponse"},"example":{"data":{"id":"payment_9f3a2b","direction":"Example direction","amount":"120.00","currency":"EUR","date":"2026-09-01T08:00:00.000Z","type":"Example type","treasuryAccountId":"treasury_account_9f3a2b","contactId":"contact_9f3a2b","reference":"2026-0001","linkedDocuments":[{"type":"invoice","id":"linked_document_9f3a2b","amount":"120.00"}],"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/treasury/get-a-payment"}},"patch":{"operationId":"updatePayment","tags":["Treasury"],"summary":"Update a payment","description":"Corrects an already recorded payment or marks it as reconciled with the bank statement. `reconciled` and `notes` are accepted and not returned: they are state of the internal accounting process. The date follows the rule of the creation: any time of today, not a later day in the time zone of the account (400 on `date`). A new amount moves the assignment only when the whole payment was assigned to a single document or order; on any other payment only the unassigned part changes, so the documents keep what they had collected, and an amount below what is already assigned responds 409 `conflict` without writing. A refunded deposit, and the refund itself, keep their amount and direction: changing either responds 409 `conflict` and nothing is written. If the documents linked to the payment keep changing while it is saved, it also responds 409 `conflict`, nothing is written and the call can be retried. Returns the full payment, the same projection as its GET.\n\n**Required scope:** `treasury:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"treasury:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Treasury payment identifier."},"required":true,"description":"Treasury payment identifier.","name":"paymentId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentUpdateBody"},"example":{"reconciled":true,"reference":"Transf. 4471-A (conciliada)"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentResponse"},"example":{"data":{"id":"payment_9f3a2b","direction":"Example direction","amount":"120.00","currency":"EUR","date":"2026-09-01T08:00:00.000Z","type":"Example type","treasuryAccountId":"treasury_account_9f3a2b","contactId":"contact_9f3a2b","reference":"2026-0001","linkedDocuments":[{"type":"invoice","id":"linked_document_9f3a2b","amount":"120.00"}],"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/treasury/update-a-payment"}}},"/api/v1/treasury/payments/{paymentId}/links":{"post":{"operationId":"linkPayment","tags":["Treasury"],"summary":"Link a payment to a document","description":"Ties an already recorded payment to the invoice, credit note, quote, proforma or purchase order it settles. It is a plural sub-resource because a payment can end up tied to several documents. Returns the full payment, with `linkedDocuments` as they now stand, the same projection as its GET.\n\n**Required scope:** `treasury:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"treasury:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Treasury payment identifier."},"required":true,"description":"Treasury payment identifier.","name":"paymentId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentLinkBody"},"example":{"linkedDocumentType":"supplierInvoice","linkedDocumentId":"sin_00904"}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentResponse"},"example":{"data":{"id":"payment_9f3a2b","direction":"Example direction","amount":"120.00","currency":"EUR","date":"2026-09-01T08:00:00.000Z","type":"Example type","treasuryAccountId":"treasury_account_9f3a2b","contactId":"contact_9f3a2b","reference":"2026-0001","linkedDocuments":[{"type":"invoice","id":"linked_document_9f3a2b","amount":"120.00"}],"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/treasury/link-a-payment-to-a-document"}}},"/api/v1/orders/{orderId}/cancel":{"post":{"operationId":"cancelOrder","tags":["Orders"],"summary":"Cancel an order","description":"Cancels the order and releases what it had reserved: frees the stock, cancels the logistics tasks —preparation, shipping and pickup— and marks the linked documents. `meta.tasksDeleted` says how many tasks were cancelled, because your schedule changes with this call. It is NOT reversible from the API: to have it back you have to duplicate it (`/unreserve` on a cancelled order responds 409 `conflict`, it does not return it to draft). An order already checked in (`checked_in`) cannot be cancelled (409 `conflict`, naming its status); one already cancelled is returned as it is. 404 if the order does not exist, belongs to another account or is archived. Returns the full order, the same projection as its GET.\n\n**Required scope:** `orders:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"orders:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Order identifier."},"required":true,"description":"Order identifier.","name":"orderId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelOrderResponse"},"example":{"data":{"id":"order_9f3a2b","orderNumber":"2026-0001","externalReference":"2026-0001","status":"draft","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","rentalDays":1,"projectId":"project_9f3a2b","projectName":"Example project name","contact":{"id":"contact_9f3a2b","name":"Example contact"},"itemsCount":1,"subTotalPrice":"120.00","discountTotal":"120.00","insuranceTotal":"120.00","depositTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"customFields":{"example":"example"},"source":"Example source","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","billingAddress":{"label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES"},"shippingAddress":{"label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES"},"contactPerson":{"id":"contact_person_9f3a2b","name":"Example contact person"},"quotes":[{"id":"quote_9f3a2b","number":"2026-0001","status":"Example status"}],"invoices":[{"id":"invoice_9f3a2b","number":"2026-0001","status":"Example status"}],"proformas":[{"id":"proforma_9f3a2b","number":"2026-0001","status":"Example status"}]},"meta":{"tasksDeleted":1}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/orders/cancel-an-order"}}},"/api/v1/orders/{orderId}/archive":{"put":{"operationId":"archiveOrder","tags":["Orders"],"summary":"Archive or restore an order","description":"Takes the order out of the active views or brings it back to them. It deletes nothing and touches neither the stock, nor the lines, nor the documents: only the visibility. PUT because the call SETS the value —there is no toggle—, so repeating it does nothing new. Only a draft or cancelled order can be archived: any other status responds 409 `conflict`, naming it. Responds 204 with no body: an archived order is no longer visible to the API (its GET responds 404), and a restored one is read again with its GET.\n\n**Required scope:** `orders:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"orders:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Order identifier."},"required":true,"description":"Order identifier.","name":"orderId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderArchiveBody"},"example":{"archived":true}}}},"responses":{"204":{"description":"No content.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/orders/archive-or-restore-an-order"}}},"/api/v1/items/{itemId}/accessories":{"put":{"operationId":"updateItemAccessories","tags":["Items"],"summary":"Update the accessories of an item","description":"Applies operations on the accessories list. READ `mode` BEFORE CALLING: with `merge` —the default— the operations are deltas and what you do not name is kept; with `replace` the list sent is the final one and EVERYTHING absent is DELETED. An accessory can be another catalog item or a custom one with its name and its price. Returns the full item, with `accessoryIds` as they now stand, the same projection as its GET.\n\n**Required scope:** `items:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"items:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Item identifier."},"required":true,"description":"Item identifier.","name":"itemId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemAccessoriesBody"},"example":{"mode":"merge","operations":[{"action":"create","accessory":{"itemId":"itm_00311","quantity":2,"free":true,"default":true}},{"action":"delete","accessoryId":"acc_00088","accessory":{"itemId":"itm_00204","quantity":1,"free":false,"default":false}}]}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemDetailResponse"},"example":{"data":{"id":"item_9f3a2b","name":"Example item","sku":"CAM-FX6-01","description":"Example text.","orderInfo":"Example order info","ean":"0000000000000","itemType":"fixed","stockCalculationMethod":"bulk","collectionId":"collection_9f3a2b","collectionName":"Example collection name","images":["Example images"],"salePrice":"120.00","depositValue":"120.00","minStock":1,"serializedItemsCount":1,"pricingSettings":{"type":"periodPrice","price":"120.00","period":"hour"},"insuranceEnabled":true,"discountEnabled":true,"bufferBefore":1,"bufferBeforeUnit":"hour","bufferAfter":1,"bufferAfterUnit":"hour","physicalProperties":{"weight":1,"width":1,"height":1,"length":1,"volume":1,"current":1,"power":1},"variants":[{"variantId":"variant_9f3a2b","variantName":"Example variant name","variantPrice":"120.00","salePrice":"120.00","ean":"0000000000000"}],"tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"customFields":{"example":"example"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","replacementValue":"120.00","accessoryIds":["accessory_9f3a2b"],"alternativeIds":["alternative_9f3a2b"]}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/items/update-the-accessories-of-an-item"}}},"/api/v1/items/{itemId}/alternatives":{"put":{"operationId":"updateItemAlternatives","tags":["Items"],"summary":"Update the alternatives of an item","description":"Declares which other items serve when this one is not available. Same `mode` contract as accessories: `merge` is deltas, `replace` deletes what is absent. Returns the full item, with `alternativeIds` as they now stand, the same projection as its GET.\n\n**Required scope:** `items:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"items:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Item identifier."},"required":true,"description":"Item identifier.","name":"itemId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemAlternativesBody"},"example":{"mode":"replace","operations":[{"action":"create","alternative":{"itemId":"itm_00512","notes":"Mismo sensor, montura distinta"}}]}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemDetailResponse"},"example":{"data":{"id":"item_9f3a2b","name":"Example item","sku":"CAM-FX6-01","description":"Example text.","orderInfo":"Example order info","ean":"0000000000000","itemType":"fixed","stockCalculationMethod":"bulk","collectionId":"collection_9f3a2b","collectionName":"Example collection name","images":["Example images"],"salePrice":"120.00","depositValue":"120.00","minStock":1,"serializedItemsCount":1,"pricingSettings":{"type":"periodPrice","price":"120.00","period":"hour"},"insuranceEnabled":true,"discountEnabled":true,"bufferBefore":1,"bufferBeforeUnit":"hour","bufferAfter":1,"bufferAfterUnit":"hour","physicalProperties":{"weight":1,"width":1,"height":1,"length":1,"volume":1,"current":1,"power":1},"variants":[{"variantId":"variant_9f3a2b","variantName":"Example variant name","variantPrice":"120.00","salePrice":"120.00","ean":"0000000000000"}],"tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"customFields":{"example":"example"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","replacementValue":"120.00","accessoryIds":["accessory_9f3a2b"],"alternativeIds":["alternative_9f3a2b"]}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/items/update-the-alternatives-of-an-item"}}},"/api/v1/items/{itemId}/variants/{variantId}":{"patch":{"operationId":"updateItemVariant","tags":["Items"],"summary":"Update a variant of an item","description":"Changes the name, the rental rate, the sale price or the barcode of a variant. The internal and external cost of the variant are not accepted: they are what serving it costs the company, and crossed with the rate they give the margin. Returns the full item, with its `variants`, the same projection as its GET.\n\n**Required scope:** `items:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"items:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Item identifier."},"required":true,"description":"Item identifier.","name":"itemId","in":"path"},{"schema":{"type":"string","minLength":1,"description":"Variant identifier."},"required":true,"description":"Variant identifier.","name":"variantId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemVariantUpdateBody"},"example":{"variantName":"Montura EF","variantPrice":"95.00","ean":"0000000000000"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemDetailResponse"},"example":{"data":{"id":"item_9f3a2b","name":"Example item","sku":"CAM-FX6-01","description":"Example text.","orderInfo":"Example order info","ean":"0000000000000","itemType":"fixed","stockCalculationMethod":"bulk","collectionId":"collection_9f3a2b","collectionName":"Example collection name","images":["Example images"],"salePrice":"120.00","depositValue":"120.00","minStock":1,"serializedItemsCount":1,"pricingSettings":{"type":"periodPrice","price":"120.00","period":"hour"},"insuranceEnabled":true,"discountEnabled":true,"bufferBefore":1,"bufferBeforeUnit":"hour","bufferAfter":1,"bufferAfterUnit":"hour","physicalProperties":{"weight":1,"width":1,"height":1,"length":1,"volume":1,"current":1,"power":1},"variants":[{"variantId":"variant_9f3a2b","variantName":"Example variant name","variantPrice":"120.00","salePrice":"120.00","ean":"0000000000000"}],"tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"customFields":{"example":"example"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","replacementValue":"120.00","accessoryIds":["accessory_9f3a2b"],"alternativeIds":["alternative_9f3a2b"]}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/items/update-a-variant-of-an-item"}}},"/api/v1/planner/resources":{"get":{"operationId":"listPlannerResources","tags":["Planner"],"summary":"List the assignable resources","description":"The other half of the planner: `/planner/services` says what has to be covered and this one, with whom. Returns the staff, the fleet or both. The date range is optional and goes as a pair; when you send it, the list is narrowed to the resources active in that window. It does not paginate.\n\n**Required scope:** `planner:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"planner:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","enum":["staff","vehicle","both"],"description":"Which resources to list: staff, fleet or both."},"required":true,"description":"Which resources to list: staff, fleet or both.","name":"resourceType","in":"query"},{"schema":{"type":"string","format":"date-time","description":"Window start, in ISO 8601 with offset. Goes with `endDate`."},"required":false,"description":"Window start, in ISO 8601 with offset. Goes with `endDate`.","name":"startDate","in":"query"},{"schema":{"type":"string","format":"date-time","description":"Window end, in ISO 8601 with offset. Goes with `startDate`."},"required":false,"description":"Window end, in ISO 8601 with offset. Goes with `startDate`.","name":"endDate","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlannerResourceItems"},"example":{"data":[{"id":"planner_resource_9f3a2b","name":"Example planner resource","type":"Example type"}]}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/planner/list-the-assignable-resources"}}},"/api/v1/credit-notes":{"get":{"operationId":"listCreditNotes","tags":["Credit notes"],"summary":"List credit notes","description":"Returns the credit notes issued to customers, cursor-paginated: what is refunded and against which invoice. Filter by lifecycle status, contact, source order, project, rectified invoice and issue date. The signed tax document, the tax breakdown, the lines and the reason for the correction are not published. Sorted by issue date, most recent first.\n\n**Required scope:** `invoices:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"invoices:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdOn","in":"query"},{"schema":{"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdAfter","in":"query"},{"schema":{"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdBefore","in":"query"},{"schema":{"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdFrom","in":"query"},{"schema":{"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdTo","in":"query"},{"schema":{"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedOn","in":"query"},{"schema":{"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedAfter","in":"query"},{"schema":{"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedBefore","in":"query"},{"schema":{"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedFrom","in":"query"},{"schema":{"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedTo","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, issueDate, grossPrice. Defaults to \"-issueDate\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, issueDate, grossPrice. Defaults to \"-issueDate\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["draft","validated","voided"],"description":"Filter by document lifecycle status: draft, validated or voided."},"required":false,"description":"Filter by document lifecycle status: draft, validated or voided.","name":"status","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["draft","validated","voided"]},"minItems":1,"maxItems":50,"description":"Filter by status, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by status, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"statuses","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by identifier of the contact the credit note is issued to."},"required":false,"description":"Filter by identifier of the contact the credit note is issued to.","name":"contactId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by contactId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by contactId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"contactIds","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by identifier of the source order of the credit note."},"required":false,"description":"Filter by identifier of the source order of the credit note.","name":"orderId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by orderId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by orderId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"orderIds","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by identifier of the project linked to the credit note."},"required":false,"description":"Filter by identifier of the project linked to the credit note.","name":"projectId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by projectId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by projectId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"projectIds","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by identifier of the invoice the credit note rectifies."},"required":false,"description":"Filter by identifier of the invoice the credit note rectifies.","name":"invoiceId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by invoiceId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by invoiceId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"invoiceIds","in":"query"},{"schema":{"description":"The credit note issue date falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The credit note issue date falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"issueDateOn","in":"query"},{"schema":{"description":"The credit note issue date is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The credit note issue date is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"issueDateAfter","in":"query"},{"schema":{"description":"The credit note issue date is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The credit note issue date is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"issueDateBefore","in":"query"},{"schema":{"description":"The credit note issue date is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The credit note issue date is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"issueDateFrom","in":"query"},{"schema":{"description":"The credit note issue date is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The credit note issue date is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"issueDateTo","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditNoteList"},"example":{"data":[{"id":"credit_note_9f3a2b","creditNoteNumber":"2026-0001","status":"draft","issueDate":"2026-09-01T08:00:00.000Z","currency":"EUR","contactId":"contact_9f3a2b","invoiceId":"invoice_9f3a2b","subTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/credit-notes/list-credit-notes"}}},"/api/v1/credit-notes/{creditNoteId}":{"get":{"operationId":"getCreditNote","tags":["Credit notes"],"summary":"Get a credit note","description":"Returns a credit note by its identifier: what is refunded to the customer and against which invoice, the same card as `GET /api/v1/credit-notes`. The signed tax document, the tax breakdown, the lines and the reason for the correction are not published.\n\n**Required scope:** `invoices:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"invoices:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Credit note identifier."},"required":true,"description":"Credit note identifier.","name":"creditNoteId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditNoteResponse"},"example":{"data":{"id":"credit_note_9f3a2b","creditNoteNumber":"2026-0001","status":"draft","issueDate":"2026-09-01T08:00:00.000Z","currency":"EUR","contactId":"contact_9f3a2b","invoiceId":"invoice_9f3a2b","subTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/credit-notes/get-a-credit-note"}}},"/api/v1/proformas":{"get":{"operationId":"listProformas","tags":["Proformas"],"summary":"List proformas","description":"Returns the proformas of the account, cursor-paginated, with the same card as the detail read: number, lifecycle and commercial status, customer (id and name), source order, project, currency and amounts. Lines, addresses and notes are not published. Filter by commercial status (pending, confirmed, cancelled), contact, source order, project and issue date. Sorted by issue date, most recent first. It shares scope with invoices because a proforma is the invoice that is not one yet.\n\n**Required scope:** `invoices:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"invoices:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdOn","in":"query"},{"schema":{"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdAfter","in":"query"},{"schema":{"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdBefore","in":"query"},{"schema":{"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdFrom","in":"query"},{"schema":{"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdTo","in":"query"},{"schema":{"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedOn","in":"query"},{"schema":{"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedAfter","in":"query"},{"schema":{"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedBefore","in":"query"},{"schema":{"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedFrom","in":"query"},{"schema":{"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedTo","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, issueDate, proformaNumber. Defaults to \"-issueDate\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: createdAt, updatedAt, issueDate, proformaNumber. Defaults to \"-issueDate\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["pending","confirmed","cancelled"],"description":"Filter by commercial status: pending (awaiting an answer), confirmed (accepted by the customer) or cancelled (rejected or cancelled)."},"required":false,"description":"Filter by commercial status: pending (awaiting an answer), confirmed (accepted by the customer) or cancelled (rejected or cancelled).","name":"operativeStatus","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["pending","confirmed","cancelled"]},"minItems":1,"maxItems":50,"description":"Filter by operativeStatus, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by operativeStatus, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"operativeStatuses","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by identifier of the contact the proforma is issued to."},"required":false,"description":"Filter by identifier of the contact the proforma is issued to.","name":"contactId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by contactId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by contactId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"contactIds","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by identifier of the source order of the proforma."},"required":false,"description":"Filter by identifier of the source order of the proforma.","name":"orderId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by orderId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by orderId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"orderIds","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Filter by identifier of the project linked to the proforma, directly or through its order."},"required":false,"description":"Filter by identifier of the project linked to the proforma, directly or through its order.","name":"projectId","in":"query"},{"schema":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"minItems":1,"maxItems":50,"description":"Filter by projectId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by projectId, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"projectIds","in":"query"},{"schema":{"description":"The proforma issue date falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The proforma issue date falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"issueDateOn","in":"query"},{"schema":{"description":"The proforma issue date is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The proforma issue date is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"issueDateAfter","in":"query"},{"schema":{"description":"The proforma issue date is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The proforma issue date is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"issueDateBefore","in":"query"},{"schema":{"description":"The proforma issue date is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The proforma issue date is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"issueDateFrom","in":"query"},{"schema":{"description":"The proforma issue date is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The proforma issue date is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"issueDateTo","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProformaList"},"example":{"data":[{"id":"proforma_9f3a2b","proformaNumber":"2026-0001","status":"Example status","operativeStatus":"Example operative status","issueDate":"2026-09-01T08:00:00.000Z","currency":"EUR","contact":{"id":"contact_9f3a2b","name":"Example contact"},"orderId":"order_9f3a2b","orderNumber":"2026-0001","projectId":"project_9f3a2b","subTotal":"120.00","discountTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","totalPaid":"120.00","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/proformas/list-proformas"}}},"/api/v1/proformas/{proformaId}":{"get":{"operationId":"getProforma","tags":["Proformas"],"summary":"Get a proforma","description":"Returns a proforma by its identifier, the same card as `GET /api/v1/proformas`: number, lifecycle and commercial status, customer, source order, project, currency and amounts. It shares scope with invoices because a proforma is the invoice that is not one yet.\n\n**Required scope:** `invoices:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"invoices:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Proforma identifier."},"required":true,"description":"Proforma identifier.","name":"proformaId","in":"path"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProformaResponse"},"example":{"data":{"id":"proforma_9f3a2b","proformaNumber":"2026-0001","status":"Example status","operativeStatus":"Example operative status","issueDate":"2026-09-01T08:00:00.000Z","currency":"EUR","contact":{"id":"contact_9f3a2b","name":"Example contact"},"orderId":"order_9f3a2b","orderNumber":"2026-0001","projectId":"project_9f3a2b","subTotal":"120.00","discountTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","totalPaid":"120.00","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/proformas/get-a-proforma"}}},"/api/v1/contacts/lookup":{"post":{"operationId":"lookupContacts","tags":["Contacts"],"summary":"Look up contacts by external reference","description":"From a list of your references, says which ones already exist in Filmo and which do not. `notFound` are the ones to create. It is the primitive of any synchronization: without it, the alternative is one call per reference and guessing from the 404. It writes NOTHING, even though it is a POST: the list of references does not fit in a query string.\n\n**Required scope:** `contacts:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"contacts:read","x-rateLimit":{"global":{"perMinute":120}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactsLookupBody"},"example":{"references":["ERP-CLI-0042","ERP-CLI-0043","ERP-CLI-9999"]}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactsLookupResultResponse"},"example":{"data":{"contacts":[{"id":"contact_9f3a2b","name":"Example contact","contactNumber":"2026-0001"}],"notFound":["Example not found"]}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/contacts/look-up-contacts-by-external-reference"}}},"/api/v1/orders/line-items/returns":{"post":{"operationId":"returnOrderLineItems","tags":["Orders"],"summary":"Return order lines","description":"Marks the returning material as returned: which line, how many units and in what condition. It hangs off the resource and not off an order because an unload crosses orders, which is what this call resolves at once. Send `Idempotency-Key`: returning the same line twice would put the material into the pool twice, and each line goes at most once per request (add up its quantities). It is a batch: `atomic` is true by default, so a line that cannot be returned rejects the whole batch with 409 and one issue per failing line, touching nothing; with `atomic: false` each order is processed on its own and the response is 207 with one result per element, where the failed ones were not returned and the rest HAVE been. On success the response is 200 with one result per element, in request order.\n\n**Required scope:** `orders:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"orders:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderLineItemsReturnBody"},"example":{"items":[{"lineItemId":"oli_00913","checkInQuantity":3,"returnCondition":"good"},{"lineItemId":"oli_01120","checkInQuantity":1,"returnCondition":"damaged"}],"checkedInAt":"2026-09-10T18:30:00+02:00"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderLineReturnResultItems"},"example":{"data":[{"index":1,"id":"order_line_return_result_9f3a2b","status":"returned","error":{"code":"Example code","message":"Example text."}}]}}}},"207":{"description":"Multi-Status (`atomic: false`): the batch was processed element by element; read each `status` and `error`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderLineReturnResultItems"},"example":{"data":[{"index":1,"id":"order_line_return_result_9f3a2b","status":"returned","error":{"code":"Example code","message":"Example text."}}]}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/orders/return-order-lines"}}},"/api/v1/ai/ask":{"post":{"operationId":"askAi","tags":["AI"],"summary":"Ask the AI about your data","description":"Answers in natural language a question about the data of your account, optionally also searching the web. It NEVER writes anything: the engine runs without a single write tool loaded, and what it can read is bounded by the permission guardrail of the owner of the API key, table by table. It consumes AI credits of the account: without quota it responds 402 addon_required without ever asking the model. It can take tens of seconds on questions that chain several queries; if `needsMoreContext` comes true, the answer is empty and you should rephrase with more detail instead of retrying the same.\n\n**Required scope:** `ai:ask`.","security":[{"bearerApiKey":[]}],"x-required-scope":"ai:ask","x-rateLimit":{"global":{"perMinute":120}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAskBody"},"example":{"question":"¿Qué pedidos tengo confirmados la semana que viene y qué material sale en ellos?","webSearch":false,"mode":"instant"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAskResponse"},"example":{"data":{"answer":"Example answer","needsMoreContext":true,"webSearchSources":[{"url":"https://example.com/resource","title":"Example title","favicon":"Example favicon"}]}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/ai/ask-the-ai-about-your-data"}}},"/api/v1/workflows":{"get":{"operationId":"listWorkflows","tags":["Workflows"],"summary":"List workflows","description":"Returns the workflows of the account with how each one starts and, for manual ones, the run form: the fields `POST /api/v1/workflows/{workflowId}/runs` requires in `payload`, read from the published version. It emits no definition. Administrators only. Sorted by name.\n\n**Required scope:** `workflows:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"workflows:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdOn","in":"query"},{"schema":{"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdAfter","in":"query"},{"schema":{"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdBefore","in":"query"},{"schema":{"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdFrom","in":"query"},{"schema":{"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdTo","in":"query"},{"schema":{"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedOn","in":"query"},{"schema":{"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedAfter","in":"query"},{"schema":{"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedBefore","in":"query"},{"schema":{"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedFrom","in":"query"},{"schema":{"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedTo","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: name, isActive, triggerType, createdAt, updatedAt. Defaults to \"name\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: name, isActive, triggerType, createdAt, updatedAt. Defaults to \"name\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"boolean","description":"Filter by whether the workflow is active (true) or paused (false)."},"required":false,"description":"Filter by whether the workflow is active (true) or paused (false).","name":"isActive","in":"query"},{"schema":{"type":"string","enum":["manual","schedule","webhook","event","signal","entity"],"description":"Filter by how the workflow starts: manual, schedule, webhook, event, signal or entity."},"required":false,"description":"Filter by how the workflow starts: manual, schedule, webhook, event, signal or entity.","name":"triggerType","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["manual","schedule","webhook","event","signal","entity"],"description":"How the workflow starts."},"minItems":1,"maxItems":50,"description":"Filter by triggerType, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by triggerType, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"triggerTypes","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkflowList"},"example":{"data":[{"id":"workflow_9f3a2b","name":"Example workflow","isActive":true,"archivedAt":"2026-09-01T08:00:00.000Z","trigger":{"type":"manual","event":"Example event","entity":"Example entity","form":[{"name":"Example form","label":"Main","type":{"example":"example"}}]},"currentVersion":{"version":1,"createdAt":"2026-09-01T08:00:00.000Z"},"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/workflows/list-workflows"}}},"/api/v1/workflows/{workflowId}/runs":{"post":{"operationId":"createWorkflowRun","tags":["Workflows"],"summary":"Run a workflow","description":"Enqueues a run of the workflow, like the \"Run\" button in the interface, and returns its identifier and the status it is born with (`queued`). **It does not wait for it to finish**, and the API has no operation that reads a run yet: its progress is only visible in the Filmo application. If the workflow declares a run form, its fields are required and travel in `payload`; if any is missing it responds 400 without enqueueing anything. A workflow without any saved version responds 409. It accepts `Idempotency-Key`: two requests with the same key return the same run instead of enqueueing two.\n\n**Required scope:** `workflows:run`.","security":[{"bearerApiKey":[]}],"x-required-scope":"workflows:run","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Identifier of the workflow to run."},"required":true,"description":"Identifier of the workflow to run.","name":"workflowId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkflowRunCreateBody"},"example":{"payload":{"numeroPedido":"P-2026-0042"}}}}},"responses":{"201":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkflowRunCreatedResponse"},"example":{"data":{"runId":"run_9f3a2b","state":"queued"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/workflows/run-a-workflow"}}},"/api/v1/orders/{orderId}/reserve":{"post":{"operationId":"reserveOrder","tags":["Orders"],"summary":"Reserve an order","description":"Moves the order to `reserved`: checks the stock of each line, deducts it and creates the delivery and return tasks. It takes no body. If there is not enough stock it responds 409 `insufficient_stock`, and `errors[]` carries one entry per short item or space (`path` is `items` or `spaces`, with `itemId`, `requested`, `available` and `shortfall`). A serial number already assigned to another order, an order that is not a draft (`prepared_partially`, `prepared`, `picked_up_partially`, `picked_up`, `returned_partially`, `returned`, `checked_in_partially`, `checked_in` or `cancelled`: the problem names its status), a sale line without source warehouse or another write on the order in progress respond 409 `conflict`. In every case nothing is reserved. 404 if the order does not exist, belongs to another account or is archived. Reserving an order that is already reserved is not an error: it changes nothing and responds 200 with `meta.tasksCreated` 0 (or the delivery and return tasks it had to restore, if some were missing). `meta.tasksCreated` says how many tasks were born, because your schedule changes with this call. It is undone with `/unreserve`. Returns the full order, the same projection as its GET.\n\n**Required scope:** `orders:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"orders:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Order identifier."},"required":true,"description":"Order identifier.","name":"orderId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReserveOrderResponse"},"example":{"data":{"id":"order_9f3a2b","orderNumber":"2026-0001","externalReference":"2026-0001","status":"draft","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","rentalDays":1,"projectId":"project_9f3a2b","projectName":"Example project name","contact":{"id":"contact_9f3a2b","name":"Example contact"},"itemsCount":1,"subTotalPrice":"120.00","discountTotal":"120.00","insuranceTotal":"120.00","depositTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"customFields":{"example":"example"},"source":"Example source","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","billingAddress":{"label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES"},"shippingAddress":{"label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES"},"contactPerson":{"id":"contact_person_9f3a2b","name":"Example contact person"},"quotes":[{"id":"quote_9f3a2b","number":"2026-0001","status":"Example status"}],"invoices":[{"id":"invoice_9f3a2b","number":"2026-0001","status":"Example status"}],"proformas":[{"id":"proforma_9f3a2b","number":"2026-0001","status":"Example status"}]},"meta":{"tasksCreated":1}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"},"insufficient_stock":{"$ref":"#/components/examples/Problem_insufficient_stock"},"order_not_reservable":{"$ref":"#/components/examples/ProblemVariant_order_not_reservable"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/orders/reserve-an-order"}}},"/api/v1/orders/{orderId}/unreserve":{"post":{"operationId":"unreserveOrder","tags":["Orders"],"summary":"Unreserve an order","description":"Undoes the reservation: returns the order to draft, frees the material it had reserved and deletes the delivery and return tasks the reservation created. `meta.tasksDeleted` says how many went away. It takes no body. It is NOT `/cancel`: cancelling is irreversible, and this order can be reserved again. Only an order in `reserved`, `prepared_partially` or `prepared` is unreserved; a draft has nothing to undo and is returned as it is, with `meta.tasksDeleted` 0. Any other status (`picked_up_partially`, `picked_up`, `returned_partially`, `returned`, `checked_in_partially`, `checked_in` or `cancelled`) responds 409 `conflict` naming it and changes nothing: a cancelled order does not go back to draft. 404 if the order does not exist, belongs to another account or is archived. Returns the full order, the same projection as its GET.\n\n**Required scope:** `orders:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"orders:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Order identifier."},"required":true,"description":"Order identifier.","name":"orderId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnreserveOrderResponse"},"example":{"data":{"id":"order_9f3a2b","orderNumber":"2026-0001","externalReference":"2026-0001","status":"draft","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","rentalDays":1,"projectId":"project_9f3a2b","projectName":"Example project name","contact":{"id":"contact_9f3a2b","name":"Example contact"},"itemsCount":1,"subTotalPrice":"120.00","discountTotal":"120.00","insuranceTotal":"120.00","depositTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"customFields":{"example":"example"},"source":"Example source","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","billingAddress":{"label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES"},"shippingAddress":{"label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES"},"contactPerson":{"id":"contact_person_9f3a2b","name":"Example contact person"},"quotes":[{"id":"quote_9f3a2b","number":"2026-0001","status":"Example status"}],"invoices":[{"id":"invoice_9f3a2b","number":"2026-0001","status":"Example status"}],"proformas":[{"id":"proforma_9f3a2b","number":"2026-0001","status":"Example status"}]},"meta":{"tasksDeleted":1}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/orders/unreserve-an-order"}}},"/api/v1/projects/{projectId}/orders/{orderId}":{"post":{"operationId":"linkProjectOrder","tags":["Projects"],"summary":"Link an order to a project","description":"Hangs the order off the project. It takes no body. It is idempotent: if it was already linked, nothing happens and the response is the same. An archived project does not admit new links and rejects the request. The order does not change customer or dates because of this. Returns the full project, the same projection as its GET.\n\n**Required scope:** `projects:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"projects:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Project identifier."},"required":true,"description":"Project identifier.","name":"projectId","in":"path"},{"schema":{"type":"string","minLength":1,"description":"Order identifier."},"required":true,"description":"Order identifier.","name":"orderId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDetailResponse"},"example":{"data":{"id":"project_9f3a2b","projectNumber":"2026-0001","name":"Example project","color":"Example color","externalReference":"2026-0001","projectTypeId":"project_type_9f3a2b","projectType":{"id":"project_type_9f3a2b","name":"Example project type","color":"Example color"},"contact":{"id":"contact_9f3a2b","name":"Example contact"},"location":{"name":"Example location","address":"Example address","city":"Madrid","postalCode":"28001","province":"Madrid","country":"ES","lat":1,"lng":1},"startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","status":"draft","archived":true,"orderIds":["order_9f3a2b"],"totalOrders":1,"tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"customFields":{"example":"example"},"source":"Example source","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/projects/link-an-order-to-a-project"}},"delete":{"operationId":"unlinkProjectOrder","tags":["Projects"],"summary":"Unlink an order from a project","description":"Takes the order out of the project. It is idempotent: if it was not linked, nothing happens and the response is the same. It does NOT delete or cancel the order: it only undoes the link, which is remade with the POST. DELETE because what disappears is the link, not either of the two entities. Returns the full project, the same projection as its GET.\n\n**Required scope:** `projects:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"projects:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Project identifier."},"required":true,"description":"Project identifier.","name":"projectId","in":"path"},{"schema":{"type":"string","minLength":1,"description":"Order identifier."},"required":true,"description":"Order identifier.","name":"orderId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDetailResponse"},"example":{"data":{"id":"project_9f3a2b","projectNumber":"2026-0001","name":"Example project","color":"Example color","externalReference":"2026-0001","projectTypeId":"project_type_9f3a2b","projectType":{"id":"project_type_9f3a2b","name":"Example project type","color":"Example color"},"contact":{"id":"contact_9f3a2b","name":"Example contact"},"location":{"name":"Example location","address":"Example address","city":"Madrid","postalCode":"28001","province":"Madrid","country":"ES","lat":1,"lng":1},"startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","status":"draft","archived":true,"orderIds":["order_9f3a2b"],"totalOrders":1,"tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"customFields":{"example":"example"},"source":"Example source","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/projects/unlink-an-order-from-a-project"}}},"/api/v1/invoices/{invoiceId}/validate":{"post":{"operationId":"validateInvoice","tags":["Invoices"],"summary":"Validate an invoice","description":"Closes a draft invoice: checks compliance, assigns it a number against its series, signs it and locks it as immutable, all in the same transaction —no gaps and no double issuance—. Only from `draft`; from any other status it rejects the request without touching anything. It validates the document AS IT IS: composing it —lines, amounts, taxes— remains the job of the editor. A validated invoice is no longer edited: it is voided. It takes no body. It requires sales documents in the plan of the account (402 without it). Returns the full invoice, the same projection as its GET.\n\n**Required scope:** `invoices:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"invoices:write","x-required-addon":["sales-documents"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Invoice identifier."},"required":true,"description":"Invoice identifier.","name":"invoiceId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceDetailResponse"},"example":{"data":{"id":"invoice_9f3a2b","invoiceNumber":"2026-0001","status":"draft","isRectification":true,"invoiceDate":"2026-09-01T08:00:00.000Z","dueDate":"2026-09-01T08:00:00.000Z","currency":"EUR","contact":{"id":"contact_9f3a2b","name":"Example contact"},"orderId":"order_9f3a2b","orderNumber":"2026-0001","projectId":"project_9f3a2b","subTotal":"120.00","discountTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","totalPaid":"120.00","paymentStatus":"unpaid","paymentMethod":"Example payment method","tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","projectName":"Example project name","taxBreakdown":[{"taxType":"120.00","label":"Main","rate":1,"baseAmount":"120.00","amount":"120.00"}],"productDiscountTotal":"120.00","globalDiscountTotal":"120.00","insuranceTotal":"120.00","depositTotal":"120.00","exchangeRate":1,"billingAddress":{"label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES"},"sourceQuoteIds":["source_quote_9f3a2b"],"sourceProformaIds":["source_proforma_9f3a2b"]}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/invoices/validate-an-invoice"}}},"/api/v1/invoices/{invoiceId}/void":{"post":{"operationId":"voidInvoice","tags":["Invoices"],"summary":"Void an invoice","description":"Voids a VALIDATED invoice with a reason, which is required and is kept. The invoice keeps its number —voiding does not release the numbering, which is what keeps the series continuous— and moves to `voided`. Only from `validated`: a draft is deleted from the application, not voided. It does NOT issue any credit note: if money has to be refunded, that is another document. Returns the full invoice, the same projection as its GET.\n\n**Required scope:** `invoices:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"invoices:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Invoice identifier."},"required":true,"description":"Invoice identifier.","name":"invoiceId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceVoidBody"},"example":{"reason":"Facturada al cliente equivocado; se reemite a Producciones Delta"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceDetailResponse"},"example":{"data":{"id":"invoice_9f3a2b","invoiceNumber":"2026-0001","status":"draft","isRectification":true,"invoiceDate":"2026-09-01T08:00:00.000Z","dueDate":"2026-09-01T08:00:00.000Z","currency":"EUR","contact":{"id":"contact_9f3a2b","name":"Example contact"},"orderId":"order_9f3a2b","orderNumber":"2026-0001","projectId":"project_9f3a2b","subTotal":"120.00","discountTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","totalPaid":"120.00","paymentStatus":"unpaid","paymentMethod":"Example payment method","tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","projectName":"Example project name","taxBreakdown":[{"taxType":"120.00","label":"Main","rate":1,"baseAmount":"120.00","amount":"120.00"}],"productDiscountTotal":"120.00","globalDiscountTotal":"120.00","insuranceTotal":"120.00","depositTotal":"120.00","exchangeRate":1,"billingAddress":{"label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES"},"sourceQuoteIds":["source_quote_9f3a2b"],"sourceProformaIds":["source_proforma_9f3a2b"]}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/invoices/void-an-invoice"}}},"/api/v1/invoices/external/{originSystem}/{originExternalId}":{"put":{"operationId":"upsertExternalInvoice","tags":["Invoices"],"summary":"Create or update the mirror of an externally issued invoice","description":"Keeps in Filmo a read-only copy of an invoice issued by ANOTHER system (an ERP such as Business Central), so the operations team can see it. Filmo does not issue it: it is not numbered against a Filmo series, not signed and never sent to Verifactu. It is stored validated, locked and marked as externally issued, and in Filmo it cannot be edited, voided, collected, rectified, e-invoiced or emailed: every change arrives through this same call. The key is the pair in the path: repeating it updates the same mirror, and repeating the same content changes nothing. Responds 201 when it creates the mirror and 200 when it updates it or it was already identical. The customer is resolved by `contactId`, then by tax ID, then by exact name (contacts are never created implicitly); one that cannot be resolved is a 400 `validation_error` whose `errors[0].path` says why: `contactId` (no such contact), `contactTaxId` (several contacts share that tax ID, or none has it and no `contactName` was sent) or `contactName` (several contacts, or none, have that name). The declared totals are checked against the lines with a tolerance of one cent per line: if they do not match it is a 400 `validation_error` with `errors[0].path` `subTotal`, `taxTotal` or `total` (also `total` when base plus taxes do not add up to it); a tax rate that cannot be recognised for a line is `lines[n].taxRate`. 409 if the invoice number is already used by another invoice of the account, if the key belongs to an invoice that is not a synced mirror, or if a voided mirror is sent back as issued. Returns the full invoice, the same projection as its GET.\n\n**Required scope:** `invoices:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"invoices:write","x-required-addon":["sales-documents"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","pattern":"^[a-z][a-z0-9_]{1,39}$","description":"Source system identifier, a lowercase slug (e.g. booqable, rentman, business_central)."},"required":true,"description":"Source system identifier, a lowercase slug (e.g. booqable, rentman, business_central).","name":"originSystem","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":200,"description":"Identifier of the document in the source system."},"required":true,"description":"Identifier of the document in the source system.","name":"originExternalId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceExternalUpsertBody"},"example":{"invoiceNumber":"FV26-001042","invoiceDate":"2026-09-15","dueDate":"2026-10-15","currency":"EUR","contactTaxId":"B00000000","lines":[{"description":"Alquiler de equipo de cámara (3 jornadas)","quantity":"3","unitPrice":"450.00","taxRate":"21"},{"description":"Transporte ida y vuelta","quantity":"1","unitPrice":"120.00","taxType":"IVA_21"}],"total":"1778.70","externalStatus":"issued","paymentStatus":"unpaid","originUrl":"https://businesscentral.dynamics.com/?company=Filmo&page=132&filter=FV26-001042"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceDetailResponse"},"example":{"data":{"id":"invoice_9f3a2b","invoiceNumber":"2026-0001","status":"draft","isRectification":true,"invoiceDate":"2026-09-01T08:00:00.000Z","dueDate":"2026-09-01T08:00:00.000Z","currency":"EUR","contact":{"id":"contact_9f3a2b","name":"Example contact"},"orderId":"order_9f3a2b","orderNumber":"2026-0001","projectId":"project_9f3a2b","subTotal":"120.00","discountTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","totalPaid":"120.00","paymentStatus":"unpaid","paymentMethod":"Example payment method","tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","projectName":"Example project name","taxBreakdown":[{"taxType":"120.00","label":"Main","rate":1,"baseAmount":"120.00","amount":"120.00"}],"productDiscountTotal":"120.00","globalDiscountTotal":"120.00","insuranceTotal":"120.00","depositTotal":"120.00","exchangeRate":1,"billingAddress":{"label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES"},"sourceQuoteIds":["source_quote_9f3a2b"],"sourceProformaIds":["source_proforma_9f3a2b"]}}}}},"201":{"description":"Created: the resource did not exist yet and was created.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceDetailResponse"},"example":{"data":{"id":"invoice_9f3a2b","invoiceNumber":"2026-0001","status":"draft","isRectification":true,"invoiceDate":"2026-09-01T08:00:00.000Z","dueDate":"2026-09-01T08:00:00.000Z","currency":"EUR","contact":{"id":"contact_9f3a2b","name":"Example contact"},"orderId":"order_9f3a2b","orderNumber":"2026-0001","projectId":"project_9f3a2b","subTotal":"120.00","discountTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","totalPaid":"120.00","paymentStatus":"unpaid","paymentMethod":"Example payment method","tags":[{"id":"tag_9f3a2b","name":"Example tag"}],"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","projectName":"Example project name","taxBreakdown":[{"taxType":"120.00","label":"Main","rate":1,"baseAmount":"120.00","amount":"120.00"}],"productDiscountTotal":"120.00","globalDiscountTotal":"120.00","insuranceTotal":"120.00","depositTotal":"120.00","exchangeRate":1,"billingAddress":{"label":"Main","addressLine1":"Calle de Ejemplo 12","addressLine2":"Calle de Ejemplo 12","city":"Madrid","province":"Madrid","postcode":"28001","country":"ES"},"sourceQuoteIds":["source_quote_9f3a2b"],"sourceProformaIds":["source_proforma_9f3a2b"]}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/invoices/create-or-update-the-mirror-of-an-externally-issued-invoice"}}},"/api/v1/credit-notes/{creditNoteId}/validate":{"post":{"operationId":"validateCreditNote","tags":["Credit notes"],"summary":"Validate a credit note","description":"Closes a draft credit note: checks compliance, assigns it a number against its series, signs it and locks it as immutable. Only from `draft`; from any other status it rejects the request without touching anything. A validated credit note is no longer edited: it is voided. It takes no body. It shares scope with invoices, just like its read. Returns the full credit note, the same projection as its GET.\n\n**Required scope:** `invoices:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"invoices:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Credit note identifier."},"required":true,"description":"Credit note identifier.","name":"creditNoteId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditNoteResponse"},"example":{"data":{"id":"credit_note_9f3a2b","creditNoteNumber":"2026-0001","status":"draft","issueDate":"2026-09-01T08:00:00.000Z","currency":"EUR","contactId":"contact_9f3a2b","invoiceId":"invoice_9f3a2b","subTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/credit-notes/validate-a-credit-note"}}},"/api/v1/credit-notes/{creditNoteId}/void":{"post":{"operationId":"voidCreditNote","tags":["Credit notes"],"summary":"Void a credit note","description":"Voids a VALIDATED credit note with a reason, which is required and is kept. It keeps its number and moves to `voided`. Only from `validated`: a draft is deleted from the application, not voided. It does not touch the invoice it was correcting. Returns the full credit note, the same projection as its GET.\n\n**Required scope:** `invoices:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"invoices:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Credit note identifier."},"required":true,"description":"Credit note identifier.","name":"creditNoteId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditNoteVoidBody"},"example":{"reason":"Importe rectificado incorrecto; se emite una nueva"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditNoteResponse"},"example":{"data":{"id":"credit_note_9f3a2b","creditNoteNumber":"2026-0001","status":"draft","issueDate":"2026-09-01T08:00:00.000Z","currency":"EUR","contactId":"contact_9f3a2b","invoiceId":"invoice_9f3a2b","subTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/credit-notes/void-a-credit-note"}}},"/api/v1/proformas/{proformaId}/status":{"patch":{"operationId":"updateProformaStatus","tags":["Proformas"],"summary":"Change the commercial status of a proforma","description":"Moves the OPERATIVE status of the proforma —`pending`, `confirmed` or `cancelled`—, which is the answer of the customer, and leaves an optional note in the history of the document. Any transition among the three is allowed, and it is undone by calling again. It does NOT touch the tax status (draft / validated): validate and void are for that. Unlike the quote, confirming a proforma does not drag any other along, because proformas have no versions. It requires sales documents in the plan of the account (402 without it). Returns the full proforma, the same projection as its GET.\n\n**Required scope:** `invoices:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"invoices:write","x-required-addon":["sales-documents"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Proforma identifier."},"required":true,"description":"Proforma identifier.","name":"proformaId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProformaStatusBody"},"example":{"status":"confirmed","notes":"Confirmada por correo el 4 de septiembre"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProformaResponse"},"example":{"data":{"id":"proforma_9f3a2b","proformaNumber":"2026-0001","status":"Example status","operativeStatus":"Example operative status","issueDate":"2026-09-01T08:00:00.000Z","currency":"EUR","contact":{"id":"contact_9f3a2b","name":"Example contact"},"orderId":"order_9f3a2b","orderNumber":"2026-0001","projectId":"project_9f3a2b","subTotal":"120.00","discountTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","totalPaid":"120.00","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/proformas/change-the-commercial-status-of-a-proforma"}}},"/api/v1/quotes/{quoteId}/status":{"patch":{"operationId":"updateQuoteStatus","tags":["Quotes"],"summary":"Change the commercial status of a quote","description":"Moves the OPERATIVE status of the active version of the quote —`pending`, `confirmed` or `cancelled`— and leaves an optional note in the history. Confirming a version moves ALL the others to `superseded`, including another one that was confirmed: it is the rule that leaves a single one in force, and it is not visible in the body. `superseded` cannot be set by hand; the system sets it. It does NOT touch the tax status (draft / validated): the document path is for that. It requires sales documents in the plan of the account (402 without it). Returns the full quote, the same projection as its GET.\n\n**Required scope:** `quotes:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"quotes:write","x-required-addon":["sales-documents"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Quote identifier."},"required":true,"description":"Quote identifier.","name":"quoteId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteStatusBody"},"example":{"status":"confirmed","notes":"Aceptada la versión 3 por teléfono"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteDetailResponse"},"example":{"data":{"id":"quote_9f3a2b","quoteNumber":"2026-0001","versionNumber":1,"status":"draft","operativeStatus":"pending","issueDate":"2026-09-01T08:00:00.000Z","validUntil":"2026-09-01T08:00:00.000Z","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","currency":"EUR","contact":{"id":"contact_9f3a2b","name":"Example contact"},"orderId":"order_9f3a2b","orderNumber":"2026-0001","projectId":"project_9f3a2b","subTotal":"120.00","discountTotal":"120.00","taxesPrice":"120.00","netPrice":"120.00","grossPrice":"120.00","totalPaid":"120.00","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z","projectName":"Example project name","taxBreakdown":[{"taxType":"120.00","label":"Main","rate":1,"baseAmount":"120.00","amount":"120.00"}]}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/quotes/change-the-commercial-status-of-a-quote"}}},"/api/v1/contracts/{contractId}/validate":{"post":{"operationId":"validateContract","tags":["Contracts"],"summary":"Validate a contract","description":"Closes a draft contract: assigns it a number from the series and locks it as immutable, in the same transaction —no gaps and no double issuance—. Only from `draft`; from any other status it rejects the request without touching anything. It moves the DOCUMENT status (`status`), not the signature status (`operativeStatus`): a validated contract remains unsigned until `/sign`. It takes no body. It requires sales documents in the plan of the account (402 without it). Returns the full contract, the same projection as its GET.\n\n**Required scope:** `contracts:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"contracts:write","x-required-addon":["sales-documents"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Contract identifier."},"required":true,"description":"Contract identifier.","name":"contractId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContractResponse"},"example":{"data":{"id":"contract_9f3a2b","contractNumber":"2026-0001","status":"draft","operativeStatus":"pending","signed":true,"signedAt":"2026-09-01T08:00:00.000Z","contactId":"contact_9f3a2b","orderId":"order_9f3a2b","orderNumber":"2026-0001","projectId":"project_9f3a2b","contractDate":"2026-09-01T08:00:00.000Z","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","grossPrice":"120.00","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/contracts/validate-a-contract"}}},"/api/v1/contracts/{contractId}/sign":{"post":{"operationId":"signContract","tags":["Contracts"],"summary":"Record the signature of a contract","description":"Marks the contract as signed and records where the signature came from: `signedVia` is `manual` if it is recorded by hand and `portal` if the customer signed it on the portal. The contract has to be VALIDATED, not voided and unsigned; in any other situation it rejects the request. It moves the SIGNATURE status (`operativeStatus`), not the document status, and `signed` is what decides whether the material can go out. The only way out of signed is voiding the document with `/void`. It requires sales documents in the plan of the account (402 without it). Returns the full contract, the same projection as its GET.\n\n**Required scope:** `contracts:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"contracts:write","x-required-addon":["sales-documents"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Contract identifier."},"required":true,"description":"Contract identifier.","name":"contractId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContractSignBody"},"example":{"signedVia":"portal"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContractResponse"},"example":{"data":{"id":"contract_9f3a2b","contractNumber":"2026-0001","status":"draft","operativeStatus":"pending","signed":true,"signedAt":"2026-09-01T08:00:00.000Z","contactId":"contact_9f3a2b","orderId":"order_9f3a2b","orderNumber":"2026-0001","projectId":"project_9f3a2b","contractDate":"2026-09-01T08:00:00.000Z","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","grossPrice":"120.00","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/contracts/record-the-signature-of-a-contract"}}},"/api/v1/contracts/{contractId}/void":{"post":{"operationId":"voidContract","tags":["Contracts"],"summary":"Void a contract","description":"Voids a VALIDATED contract with a reason, which is required and is kept. It keeps its number and moves to `voided`: it moves the DOCUMENT status and removes its validity, signed or not. Only from `validated`: a draft is deleted from the application, not voided. It is NOT `/cancel`, which moves the signature status and leaves the document alive. Returns the full contract, the same projection as its GET.\n\n**Required scope:** `contracts:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"contracts:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Contract identifier."},"required":true,"description":"Contract identifier.","name":"contractId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContractVoidBody"},"example":{"reason":"Emitido con la razón social equivocada; se emite uno nuevo"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContractResponse"},"example":{"data":{"id":"contract_9f3a2b","contractNumber":"2026-0001","status":"draft","operativeStatus":"pending","signed":true,"signedAt":"2026-09-01T08:00:00.000Z","contactId":"contact_9f3a2b","orderId":"order_9f3a2b","orderNumber":"2026-0001","projectId":"project_9f3a2b","contractDate":"2026-09-01T08:00:00.000Z","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","grossPrice":"120.00","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/contracts/void-a-contract"}}},"/api/v1/contracts/{contractId}/cancel":{"post":{"operationId":"cancelContract","tags":["Contracts"],"summary":"Cancel a contract operatively","description":"Gives the contract up as not signable: it moves its SIGNATURE status (`operativeStatus`) to `cancelled` and leaves the document alive, with its number. The reason is optional and is kept in the history. An ALREADY SIGNED contract cannot be cancelled —it rejects the request—: to undo a signature you have to void the document with `/void`. `cancelled` is terminal: a cancelled contract can no longer be signed. Returns the full contract, the same projection as its GET.\n\n**Required scope:** `contracts:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"contracts:write","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Contract identifier."},"required":true,"description":"Contract identifier.","name":"contractId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContractCancelBody"},"example":{"reason":"El cliente se echa atrás antes de firmar"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContractResponse"},"example":{"data":{"id":"contract_9f3a2b","contractNumber":"2026-0001","status":"draft","operativeStatus":"pending","signed":true,"signedAt":"2026-09-01T08:00:00.000Z","contactId":"contact_9f3a2b","orderId":"order_9f3a2b","orderNumber":"2026-0001","projectId":"project_9f3a2b","contractDate":"2026-09-01T08:00:00.000Z","startDate":"2026-09-01T08:00:00.000Z","endDate":"2026-09-01T08:00:00.000Z","grossPrice":"120.00","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/contracts/cancel-a-contract-operatively"}}},"/api/v1/supplier-invoices/{supplierInvoiceId}/validate":{"post":{"operationId":"validateSupplierInvoice","tags":["Supplier invoices"],"summary":"Validate a supplier invoice","description":"Approves a draft received invoice: checks the required fields, assigns it an internal number from the series and locks it as immutable. Only from `draft`; from any other status it rejects the request without touching anything. It requires supplier, invoice file, date, at least one line and a total amount greater than zero; if any is missing it responds 409 `conflict` listing what a validatable invoice needs (it does not name the missing one: complete the invoice in the app). There is no tax compliance: the invoice is received, not issued. It takes no body. It requires the purchases add-on (402 without it). Returns the full invoice, the same projection as its GET.\n\n**Required scope:** `supplier-invoices:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"supplier-invoices:write","x-required-addon":["purchases"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Supplier invoice identifier."},"required":true,"description":"Supplier invoice identifier.","name":"supplierInvoiceId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierInvoiceResponse"},"example":{"data":{"id":"supplier_invoice_9f3a2b","supplierInvoiceNumber":"2026-0001","status":"Example status","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/supplier-invoices/validate-a-supplier-invoice"}}},"/api/v1/supplier-invoices/{supplierInvoiceId}/void":{"post":{"operationId":"voidSupplierInvoice","tags":["Supplier invoices"],"summary":"Void a supplier invoice","description":"Voids an already VALIDATED received invoice with a reason, which is required and is kept. It keeps its internal number —voiding does not release the numbering— and moves to `voided`. Only from `validated`: a draft is deleted from the application, not voided. It does not touch the treasury payment that may have paid it or the purchase order that originated it. It requires the purchases add-on (402 without it). Returns the full invoice, the same projection as its GET.\n\n**Required scope:** `supplier-invoices:write`.","security":[{"bearerApiKey":[]}],"x-required-scope":"supplier-invoices:write","x-required-addon":["purchases"],"x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","minLength":1,"description":"Supplier invoice identifier."},"required":true,"description":"Supplier invoice identifier.","name":"supplierInvoiceId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":255,"example":"9f1c2f4e-3a5b-4f6d-8e7a-0b1c2d3e4f5a"},"required":false,"description":"Unique identifier of the request, chosen by the client (a UUID works). Between 1 and 255 characters: an empty header is rejected with 400 `validation_error`, because the client would believe itself protected. Repeating the same key with the SAME body within 24 h returns the stored response without executing again, with the `Idempotent-Replay: true` header. With a DIFFERENT body it returns 422. It is the safe way to retry after a network timeout.","name":"Idempotency-Key","in":"header"},{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Optimistic locking: the `ETag` you read from the resource (or `*`). If the resource changed since, the write is rejected with `412 precondition_failed` before doing anything; read it again and retry. Without the header the write always proceeds.","name":"If-Match","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierInvoiceVoidBody"},"example":{"reason":"Llegó duplicada; la buena es la del 3 de septiembre"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierInvoiceResponse"},"example":{"data":{"id":"supplier_invoice_9f3a2b","supplierInvoiceNumber":"2026-0001","status":"Example status","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"402":{"description":"Add-on required (addon_required): the account plan does not include the add-on this operation needs; `requiredAddon` names it.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"addon_required":{"$ref":"#/components/examples/Problem_addon_required"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"404":{"description":"Resource not found (not_found): it does not exist or is outside the scope of the API key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"not_found":{"$ref":"#/components/examples/Problem_not_found"}}}}},"409":{"description":"Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"conflict":{"$ref":"#/components/examples/Problem_conflict"}}}}},"412":{"description":"Precondition failed (precondition_failed): the `If-Match` entity tag does not match the current representation. Read the resource again and retry.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"precondition_failed":{"$ref":"#/components/examples/Problem_precondition_failed"}}}}},"422":{"description":"Idempotency-Key reused (idempotency_key_reused): the same key was used before with a different body. Change the key.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"idempotency_key_reused":{"$ref":"#/components/examples/Problem_idempotency_key_reused"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Idempotent-Replay":{"$ref":"#/components/headers/Idempotent-Replay"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/supplier-invoices/void-a-supplier-invoice"}}},"/api/v1/account":{"get":{"operationId":"getAccount","tags":["Account"],"summary":"Get the account","description":"Returns the account that made the request: its name, the timezone bare days are read in, its currency and country, the add-ons it has access to (a resource behind an add-on not listed responds 402), whether it is in its trial period, the API key that made the request with its scopes, the usage limits the RateLimit-* headers report, and the version of this contract. It is the first call of any integration: it replaces guessing.\n\n**Required scope:** `account:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"account:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"string","example":"\"3sT3d9pBvZq4h2N0w8x1YkLmQ7c\""},"required":false,"description":"Conditional read: the `ETag` of the copy you already have. If the resource has not changed, the response is `304` with no body.","name":"If-None-Match","in":"header"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"ETag":{"$ref":"#/components/headers/ETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountResponse"},"example":{"data":{"name":"Example account","timezone":"Europe/Madrid","currency":"EUR","country":"ES","language":"es-ES","addons":["platform"],"trial":{"active":true,"endsAt":"2026-09-01T08:00:00.000Z"},"apiKey":{"id":"api_key_9f3a2b","name":"Example api key","scopes":["Example scopes"]},"rateLimits":{"global":{"perMinute":50},"availability":{"perMinute":50}},"api":{"version":"Example version","docsUrl":"https://example.com/resource"}}}}}},"304":{"description":"Not modified: the `If-None-Match` sent matches the current `ETag`. No body; the copy you have is current.","headers":{"ETag":{"$ref":"#/components/headers/ETag"}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/account/get-the-account"}}},"/api/v1/payment-methods":{"get":{"operationId":"listPaymentMethods","tags":["Treasury"],"summary":"List payment methods","description":"Returns the payment methods configured in the account, sorted by name: what `paymentMethodId` expects when recording a payment. Filter by type and archive state. Payment instructions and bank details are not published.\n\n**Required scope:** `treasury:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"treasury:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: name, type, createdAt, updatedAt. Defaults to \"name\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: name, type, createdAt, updatedAt. Defaults to \"name\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["bank_transfer","card","cash","other","sepa_direct_debit"],"description":"Filter by payment method type: bank_transfer, card, cash, other or sepa_direct_debit."},"required":false,"description":"Filter by payment method type: bank_transfer, card, cash, other or sepa_direct_debit.","name":"type","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["bank_transfer","card","cash","other","sepa_direct_debit"],"description":"Payment method type: bank_transfer, card, cash, other or sepa_direct_debit."},"minItems":1,"maxItems":50,"description":"Filter by type, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by type, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"types","in":"query"},{"schema":{"type":"boolean","description":"Filter by archive state: false for the methods currently offered, true for the archived ones. Absent means both."},"required":false,"description":"Filter by archive state: false for the methods currently offered, true for the archived ones. Absent means both.","name":"isArchived","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentMethodList"},"example":{"data":[{"id":"payment_method_9f3a2b","name":"Example payment method","type":"bank_transfer","isSystem":true,"isDefault":true,"isArchived":true,"createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/treasury/list-payment-methods"}}},"/api/v1/users":{"get":{"operationId":"listUsers","tags":["Users"],"summary":"List users","description":"Returns the people with access to the account — the ones who sign in to Filmo, not the staff — with their role, whether they administer the account, the status of their access (active, pending invitation or inactive) and the staff member they are linked to. It emits no credentials, sessions, permissions or preferences. Administrators only. Sorted by name.\n\n**Required scope:** `users:read`.","security":[{"bearerApiKey":[]}],"x-required-scope":"users:read","x-rateLimit":{"global":{"perMinute":120}},"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50,"description":"Page size (1-500). Defaults to 50."},"required":false,"description":"Page size (1-500). Defaults to 50.","name":"limit","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque."},"required":false,"description":"Opaque cursor of the page to return. Pass the value of `pagination.nextCursor` from the previous response; treat it as opaque.","name":"cursor","in":"query"},{"schema":{"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdOn","in":"query"},{"schema":{"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdAfter","in":"query"},{"schema":{"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdBefore","in":"query"},{"schema":{"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdFrom","in":"query"},{"schema":{"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The creation date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"createdTo","in":"query"},{"schema":{"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource falls on this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedOn","in":"query"},{"schema":{"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedAfter","in":"query"},{"schema":{"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedBefore","in":"query"},{"schema":{"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or after this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedFrom","in":"query"},{"schema":{"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}(:?\\d{2})?))?$"},"required":false,"description":"The last update date of the resource is on or before this date. A bare day (YYYY-MM-DD, read in the business timezone) or an ISO 8601 instant with offset.","name":"updatedTo","in":"query"},{"schema":{"type":"string","maxLength":200,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: name, email, status, createdAt, updatedAt. Defaults to \"name\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with."},"required":false,"description":"Sort order: up to 3 comma-separated fields, each with a leading \"-\" for descending (e.g. \"-updatedAt,name\"). Sortable fields: name, email, status, createdAt, updatedAt. Defaults to \"name\". Ties are broken by id, so the order is stable across pages, and a cursor is bound to the sort it was issued with.","name":"sort","in":"query"},{"schema":{"type":"string","enum":["active","pending","inactive"],"description":"Filter by access status: active, pending (invited, not yet accepted) or inactive."},"required":false,"description":"Filter by access status: active, pending (invited, not yet accepted) or inactive.","name":"status","in":"query"},{"schema":{"type":"array","items":{"type":"string","enum":["active","pending","inactive"],"description":"Access status."},"minItems":1,"maxItems":50,"description":"Filter by status, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them."},"required":false,"description":"Filter by status, as a list: repeat the parameter or separate the values with commas. Accepts up to 50 values and returns whatever matches any of them.","name":"statuses","in":"query"},{"schema":{"type":"boolean","description":"Filter by whether the user is an administrator of the account (true) or not (false)."},"required":false,"description":"Filter by whether the user is an administrator of the account (true) or not (false).","name":"isAdmin","in":"query"},{"schema":{"type":"boolean","default":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default."},"required":false,"description":"Set it to true to include `pagination.total`, the number of results that match the filters across all pages. Off by default.","name":"includeTotal","in":"query"}],"responses":{"200":{"description":"Successful response.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserList"},"example":{"data":[{"id":"user_9f3a2b","name":"Example user","email":"ana.garcia@example.com","role":{"id":"role_9f3a2b","name":"Example role"},"isAdmin":true,"status":"active","staffMemberId":"staff_member_9f3a2b","createdAt":"2026-09-01T08:00:00.000Z","updatedAt":"2026-09-01T08:00:00.000Z"}],"pagination":{"nextCursor":"eyJvIjoyMH0","hasMore":true,"total":1}}}}},"400":{"description":"Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"validation_error":{"$ref":"#/components/examples/Problem_validation_error"}}}}},"401":{"description":"Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"unauthorized":{"$ref":"#/components/examples/Problem_unauthorized"},"api_key_invalid":{"$ref":"#/components/examples/Problem_api_key_invalid"},"api_key_revoked":{"$ref":"#/components/examples/Problem_api_key_revoked"},"api_key_expired":{"$ref":"#/components/examples/Problem_api_key_expired"},"api_key_owner_inactive":{"$ref":"#/components/examples/Problem_api_key_owner_inactive"},"api_key_owner_not_admin":{"$ref":"#/components/examples/Problem_api_key_owner_not_admin"}}}}},"403":{"description":"Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"insufficient_scope":{"$ref":"#/components/examples/Problem_insufficient_scope"},"forbidden":{"$ref":"#/components/examples/Problem_forbidden"}}}}},"429":{"description":"Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"rate_limited":{"$ref":"#/components/examples/Problem_rate_limited"}}}}},"500":{"description":"Internal error (internal_error).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Content-Language":{"$ref":"#/components/headers/Content-Language"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"examples":{"internal_error":{"$ref":"#/components/examples/Problem_internal_error"}}}}}},"externalDocs":{"description":"Documentation of this operation","url":"https://docs.filmo.io/rest-api/endpoint-reference/users/list-users"}}}},"webhooks":{}}