POST /v1/invoices/imports. There is no generic task
submission endpoint. Import admission/retry returns import_id, workflow_run_id, and
workflow_run_item_id; the import’s summary/detail also identify its current run and item.
Known primary-file duplicates detected before admission create neither a run nor an item.
The preview exposes invoice_import, invoice_import_batch, invoice_agreement_matching,
agreement_invoice_matching, invoice_compliance_check, agreement_compliance_check,
alert_topic_reconciliation, alert_topic_proposal, agreement_context_suggestions,
document_extraction, agreement_document_classification, agreement_detail_suggestions and
integration_sync workflows. An invoice check has one item per agreement and an agreement check
one item per invoice; see
compliance checks. After a check, an alert_topic_reconciliation
run with one item organises the agreement’s alerts into topics; at most one is active per
agreement. Each extraction, classification or detail-suggestion request has one item.
Classification and detail-suggestion items identify the agreement and contain the proposed role
or details; extraction items identify the Document.
See agreement suggestions.
Matching items always identify invoices; an invoice refresh
has one item, while an agreement refresh discovers invoice items in bounded pages. See
Explicit matching for commands and relationship results. Workflow responses contain business progress and results; source
evidence is available through the import resource.
Endpoints and permissions
Send a bearer credential and
X-Organization-Id. Workflow reads require Read; cancellation requires
Write. OpenAPI records each operation’s level in x-watchdog-permission. Lists include only the
shipped public workflow inventory in the target organization. Unknown, foreign, or internal run IDs
return 404; an item must belong to the requested run and organization. Insufficient access returns 403.
Background progress
UseGET /v1/workflow-runs/summary for background observation. It returns one entry per public
workflow type, including idle types. run_counts covers all retained runs by status;
progress covers items belonging to currently active runs only. discovering_run_count reports
open discovery, in which case progress.total is null. A zero total is a valid empty operation.
Each entry has an opaque change_token derived from run counts and active progress. Terminal
counts ensure the token changes when work finishes, even if the active run count is unchanged.
This is a snapshot token, not a durable event cursor or an exactly-once notification mechanism.
Use token changes to invalidate related application data; establish a baseline on first load.
Poll this summary once every five seconds while active, stop polling when idle, and pause
in hidden tabs, and honor Retry-After. Load individual runs and item results through the paginated
endpoints only when needed. Do not drain the full run inventory on every polling interval.
Run representation
Lists and individual run reads use the same fixed shape:resource identifies the business operation owning the run. Progress counts admitted items,
not invoices ultimately created or provider records filtered out during discovery. total is null
while discovery can add items. Once the collection closes, total equals the sum of the six counts.
A total of zero is a legitimate empty operation. Counts and parent status describe the same point
in time; progress changes update the parent’s updated_at. All timestamps are UTC.
One item failure does not terminate its siblings. Completion requires both a closed collection and
no queued/running items. A fatal discovery failure remains a parent failure even if admitted items
succeed. A failed run has
failure: { code, message }; item-specific details remain on the items.
Reading a failed run or item returns HTTP 200. finished_at is set for terminal states.
Items and results
queued | running | completed | skipped | failed | cancelled. Pending items have null
result and failure. Failed items have a stable failure code/message and null result; cancelled items
have neither. Successful/skipped items retain a typed business result, available immediately
regardless of sibling or parent status. Historical items whose result was never retained have null
result.
For invoice imports, imported and duplicate results include an invoice UUID; not_invoice has
invoice_id: null. All three are completed processing outcomes. Financial inconsistency does not
fail the item: read the resulting invoice’s financially_valid and financial_errors.
Results describe the exact item execution, remain unchanged after invoice edits or explicit retry,
and contain resource references rather than copies of business documents. Publication, item result,
applicable usage, and possible parent completion commit atomically. There is no run-level /result
or separate /results collection: use /items, optionally filtered to terminal statuses.
Filtering and pagination
Run lists supportstatus, type, created_from (inclusive UTC), created_before (exclusive UTC),
resource_type, resource_id (requires resource_type), and ids (at most 100 UUIDs).
status, type, and ids accept comma-separated values. Different filters use AND; values within
one filter use OR. Omit status to include terminal runs. Run order is created_at DESC, id DESC.
When both creation bounds are supplied, created_before must be later than created_from.
Item lists support comma-separated status. Order is created_at ASC, id ASC.
Both lists return { "data": [...], "next_cursor": null }, default to 50 items and allow at most 100. Cursors bind to the organization, filters, ordering, and (for items) parent run. Continue with
the same filters. Pagination reads current state rather than a frozen snapshot. A null cursor means
there are no more matching rows at that moment, not that discovery or processing has finished.
Newly settled items can enter a status-filtered collection before an existing cursor: restart listing
when refreshing it. This is not an incremental event feed.
Polling in an application
- Share one summary query across application modules. Refresh it after successful admission and when returning to the app; use its change tokens to invalidate affected data.
- Open run lists on demand, fetching one page at a time. Do not expand the background summary into a poll for every active run or every admission ID.
- Poll the selected active run without a status filter so its terminal state remains visible. Fetch item/result pages only when the user opens them.
- Stop polling unavailable IDs. Resolve 401/403; respect
Retry-Afteracross summary, focus, and detail requests on 429. Back off for transport/5xx failures and pause while hidden.
Cache-Control: private, no-store. The generated client owns no timers; your
application controls polling.
Cancellation, retry, and recovery
Cancellation takes no body or idempotency key. It fences publication, closes discovery, and cancels queued/running items before requesting provider cancellation. Completed/skipped/failed items retain their results and failures. Repeated cancellation succeeds, including after a newer retry exists. Other terminal runs return 409conflict. A provider cancellation failure cannot reopen product work.
Retry remains a domain command: POST /v1/invoices/imports/{id}/retry validates sources and capacity
again and optionally accepts Idempotency-Key to safely replay that retry request. Explicit retries create new run and item IDs with
retry_of_run_id and retry_of_item_id; replays return the same new identities. Earlier runs/items
never reopen. Future bulk retry commands select unsuccessful items rather than redoing successes.
Automatic execution retries keep the current item identity and cannot overwrite terminal results.
If an execution stops outside the API, background recovery reconciles confirmed failure or
cancellation into the run and item. An execution that completes without publishing its business
result fails with execution_incomplete. Temporary provider unavailability does not change the
product state or cause an automatic resubmission. Retrieve the import’s failure and evidence before
choosing an explicit retry.