Skip to main content
These conventions apply to the API preview. Generated endpoint pages contain the exact fields and operation-specific responses.

Authentication and permissions

Use GET /v1/organizations without an organization header to discover your permitted organizations. See organizations, users, and teams for the complete flow. For resource requests, send your personal API key as a bearer token and target one organization explicitly:
GET /v1/me identifies the key and owner without an organization header. Organization detail returns access.role, access.configured_level, and access.effective_level. Effective access is the lower of the configured level and the owner’s current organization role. Members have Write; organization admins have Admin. Write includes Read; Admin includes Write. There are no separate related-resource grants. New keys default to Read and all organizations you have access to. All-organization access follows current and future memberships; selected access stays within the selected set. Existing organization keys are migrated to Write and remain restricted to their original organization, which is also their fallback when the header is omitted. API keys read membership, role, and account status from Watchdog’s database on each request. Clerk changes take effect after webhook synchronization. Key edits and revocation are immediate. Normal Clerk sessions use the active organization; a supplied organization header must match it. Read authentication and API keys for account, MFA, and lifecycle rules.

Values and collections

  • Business resource IDs are UUIDs; organization and user IDs are opaque strings; JSON field names use snake_case.
  • Amounts, quantities, and rates are decimal strings. "0.25" means a rate of 25%.
  • Calendar dates use YYYY-MM-DD; timestamps are UTC. Unknown source values remain null.
  • Text values must not contain null characters (\u0000).
  • Collections return { "data": [...], "next_cursor": null }. The default limit is 50; the maximum is 100.
  • Pass next_cursor as cursor with the same filters and ordering. Stop when it is null.
  • A cursor is a position in current data, not a frozen snapshot or an event subscription.
Query filters that accept several values use comma-separated values. Different filters combine with AND; values within one filter combine with OR. See each endpoint for its supported filters. Invoice metrics use the same filters as invoice lists and separate monetary totals by currency. Invoice date ranges include both endpoints; the end date must be on or after the start date. Workflow creation ranges exclude created_before, which must be later than created_from. Reversed or empty exclusive ranges return 400 with the field to correct. Requests are JSON, except file bytes sent directly to the returned storage upload URL. The complete JSON body is limited to 2 MiB, including line data. Support contact requests allow up to 32 MiB to include attachments; individual fields also have documented limits. Responses use fixed shapes with paginated relationships, rather than arbitrary field expansion.

My records and teams

Create shared teams, author predicates, and manage membership using the team management guide. Use mine=true on invoice lists and metrics, agreement lists, alert lists/metrics/groups, and claim lists and metrics. It matches the shared teams the current user belongs to in the target organization; personal API keys use their owner’s memberships. Personal subscriptions are excluded. This filters existing access and grants no additional permissions. Each team’s saved AND/OR rules are preserved. Teams combine with OR; other query filters narrow results with AND. Alternatively, select up to 50 shared teams using comma-separated team_ids. Combining mine=true and team_ids returns 400. Omitted mine or mine=false adds no membership filter; explicit team_ids still applies. Invoice rules use the invoice’s own supplier, recipient and fields, and matched agreements for agreement rules. Agreement rules use linked parties and the agreement’s fields, and matched invoices for invoice rules. Alerts use their own supplier, invoice recipient and fields, and their own agreement. Another agreement matched to the same invoice does not contribute to an alert’s agreement rules. Claims match through their agreement, including empty claims; their totals retain complete claim membership and refunds. This mapping also applies to explicit team_ids. No memberships or saved rules produces empty results and zero metrics. Missing, foreign, or personal explicit team IDs return 404; invalid saved rules return 409 conflict with an instruction to fix the team filters. This replaces silent-empty results for invalid rules. Keep the same query, organization and user when following a mine cursor. Memberships, rules and relative UTC dates are evaluated on each request, so changes can affect later pages. Pagination remains live; no snapshot or scope version is stored.

Safely retrying requests

Agreement creation, price-item creation, invoice creation, import creation, and explicit import retry accept an optional Idempotency-Key. You can make normal requests without it. To safely retry after a timeout or lost response, choose one unique value for the action (such as a UUID) and send the same value with the same input on each attempt:
Keep REQUEST_KEY for retries of this action. Use a new value for a new action. Without a key, repeated requests are separate actions and do not replay earlier responses. The invoice duplicate guard still applies: structured duplicates return 409, and imports can complete as duplicate. Concurrent import requests may start separate extraction jobs before the duplicate is known. Validation failures return 400 without committing a creation receipt. Correct the input and reuse that key. Editing an invoice never changes its creation receipt. Retrying an import creates new run/item identities; replaying the retry request returns those same identities. If a resource was permanently deleted through the legacy application, replay returns 409. That key remains reserved; use a new key for a new action. Soft-deleted invoices still replay normally.

Conditional agreement edits

Individual agreements, prices, and document relationships return a strong ETag. Send that resource’s validator in If-Match on PATCH or DELETE to avoid overwriting a concurrent change. A stale or weak validator returns 412 precondition_failed; read the current resource before reapplying the edit. Without the header, the edit applies to the locked current state. Agreement PATCH preserves omitted fields; null clears nullable fields. A supplied nested object or membership array replaces that complete field. Agreement list and detail responses include all selected suppliers and recipients; send the complete desired ID array when changing a selection. Successful nested deletion is 204. Creation returns 201 with Location; updates and replays return 200.

Errors and retries

Validation errors may include bounded details with fields to correct. Branch on error.code, not the human-readable message. Save the request ID for troubleshooting; you can send X-Request-Id to supply your own correlation ID. Correct 400, 401, and 403 failures before retrying. A resource outside your authorized organization is unavailable. Respect Retry-After on 429; back off for network errors and 5xx responses. A failed import admission may retain an error.import_id: retrieve it before deciding whether to explicitly retry. Do not assume an error means no work exists. A failed workflow run or item is still a retrievable resource: its GET returns 200, with failure information in its body. Follow the polling guide for asynchronous work.