Skip to main content

Documents and Import

Find contract and invoice documents, list contract documents that have no price model yet, queue them for background extraction, and poll the import queue.

Four routes prepare the ground for a price model. GET /v1/price-baseline/documents is the picker for contracts and invoices: it finds workspace documents by filename. GET /v1/price-baseline/import/candidates lists the documents that look like contract price documents and have no model yet, grouped by contract number. POST /v1/price-baseline/import queues documents for extraction, and GET /v1/price-baseline/import/status reports the queue. Together they are the bulk path from a document store to a set of price models.

Single extraction (POST /v1/price-baseline/models) runs the extraction model inside the request. The import queue does the same work in the background: a scheduler extracts the price models of queued documents, so a workspace can queue hundreds of documents with one call and poll for the outcome. The queue holds one entry per document with a status of pending, running, done or failed.

Candidates are workspace documents that look like contract price documents: a supply, lease, service or maintenance contract, an amendment, a price sheet. Invoices and letters are left out, and up to 2000 documents are considered. Each candidate carries a kind of contract, amendment or price_sheet, and groups form by the contract number the filename carries. Documents without a number form a group with a null contract_key, listed last.

GET/v1/price-baseline/documents

Query parameters

qstringSubstring of the filename.

Response fields

data[].iduuidDocument id. Use it as document_id or invoice_document_id in the other routes.
data[].filenamestringFilename of the document.
data[].created_atdate-timeWhen the document was added.

Response: Matching documents

{
  "data": [
    {
      "id": "3f6c1d2e-8a41-4c57-9b0e-2d7a5c1e9f10",
      "filename": "Waermeliefervertrag_4711.pdf",
      "created_at": "2025-03-11T09:14:22.000Z"
    }
  ]
}
GET/v1/price-baseline/import/candidates

Query parameters

qstringSubstring of the filename.

Response fields

data[].contract_keystring | nullContract number from the filenames of the group; null for documents without a number.
data[].documents[].document_iduuidThe document.
data[].documents[].filenamestringFilename.
data[].documents[].kindstringcontract, amendment, or price_sheet.
data[].documents[].created_atdate-timeWhen the document was added.
data[].documents[].importobject | nullThe queue entry of this document when it was queued: status (pending, running, done, failed) and error.
POST/v1/price-baseline/import

Body fields

document_ids*uuid[]Documents to queue. 1 to 500 ids.

Response fields (201)

queuedintegerDocuments queued by this call.
skippedintegerIds left as they were: not documents of the workspace, or entries that are pending, running or done.

cURL: Queue every candidate of one contract

curl -X POST "https://api.talonic.com/v1/price-baseline/import" \
  -H "Authorization: Bearer $TALONIC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"document_ids": ["3f6c1d2e-8a41-4c57-9b0e-2d7a5c1e9f10", "8d20b6c4-17fe-4a93-b5c8-6e1f0a9d3c72"]}'
GET/v1/price-baseline/import/status

Response fields

countsobjectNumber of queue entries per status (pending, running, done, failed). Statuses without entries are absent.
failed[]arrayThe 20 latest failed entries: document_id, filename, error, attempts.

Response: Queue state

{
  "counts": { "pending": 12, "running": 3, "done": 140, "failed": 1 },
  "failed": [
    {
      "document_id": "8d20b6c4-17fe-4a93-b5c8-6e1f0a9d3c72",
      "filename": "Preisblatt_2024.pdf",
      "error": "The extraction model returned no price components.",
      "attempts": 2
    }
  ]
}
Queuing is idempotent per document. Calling POST /v1/price-baseline/import twice with the same ids does not extract a document twice: entries that are pending, running or done are left alone and counted in skipped, and only failed entries are queued again.

Frequently asked questions

What is the difference between importing and extracting a model?+
Extracting with POST /v1/price-baseline/models runs the extraction model inside the request and returns the stored draft model. Importing queues documents and returns immediately with counts; a scheduler extracts the models in the background, and GET /v1/price-baseline/import/status reports progress and the latest failures.
Why does a document not appear among the candidates?+
Candidates are documents that look like contract price documents and have no model yet. Invoices and letters are left out, documents that already have a model are left out, and at most 2000 documents are considered. Use GET /v1/price-baseline/documents with a filename filter to find any document regardless of kind.
What happens to a failed queue entry?+
Queuing the same document again queues the failed entry again. The status route lists the 20 latest failures with the error and the number of attempts, so a failure can be inspected before retrying. Entries that are pending, running or done are never queued twice.