X-Organization-Id on every API request to select an organization allowed by the key and your
current membership. Create keys under Settings → Personal → API keys; see
authentication and API keys for role limits and organization access.
This walkthrough uses existing supplier and recipient records.
Create an agreement and select parties
Creation accepts every editable agreement field:title, status, supplier_ids, recipient_ids, tag_ids,
effective_date, expiration_date, applicability, renewal, instructions, alert_settings, and matching_settings. Status defaults to draft.
Set status to active to create an active agreement with a nonblank title. Agreements, prices and
document relationships remain editable in every status, including archived. For example:
API_URL, API_KEY, and ORGANIZATION_ID for your environment as shown in the quickstart. You can also create an empty draft and edit it later:
supplier_ids array matches no
invoices, including when the agreement is activated. An empty recipient_ids array means any
recipient. Both arrays default to empty. Both suppliers and recipients responses have the same
complete array shape. Within each selection, any listed ID may match; the two selections combine
with AND.
PATCH preserves omitted fields and clears nullable fields when given null. Each supplied nested
object or membership array replaces the complete field. For example, supplying recipient_ids
replaces the entire recipient selection. Agreement list and detail responses include every selected
supplier and recipient as { id, name, organization_number } objects in plain arrays, ordered by ID.
There is no membership count cap or separate membership endpoint. The common request-body size limit applies.
Organize agreements with tags
List the organization catalogue or create a tag with Write access (which includes reads):{ id, name } with 201. Repeating a name in different case returns the
existing tag with 200, preserving its spelling. Names are trimmed and limited to 1–80 characters.
The returned Location resolves that ID through the catalogue’s ids filter.
Agreement list, detail, create and PATCH responses include every assigned tag:
tag_ids on creation or PATCH to replace the complete selection. Omission on PATCH preserves
tags; tag_ids: [] clears assignments without deleting catalogue tags. Every ID must belong to your
organization. Tags update the agreement’s ETag without invalidating compliance checks or running
workflows. Reordered or duplicated IDs are a no-op. Tag-only edits also work during background work.
The catalogue uses { data, next_cursor }, default 50/max 100, ordered by case-insensitive name then
ID. Continue with the same filters and returned cursor. GET /v1/agreements?tag_ids=<id>,<id> matches
agreements with any selected tag and combines with other filters using AND. Untagged agreements do
not match a tag filter. Catalogue reads need only Read access; creating or assigning tags
requires Write access.
Configure agreement settings
Agreement detail also includes these editable settings:instructions is the app’s context note for interpreting the agreement during compliance checks.
The alert flags control whether checks report undercharges and items outside agreement coverage.
Both default to false. Smart matching requires a nonblank criterion when enabled; the criterion
is limited to 1,000 characters. Supplying either settings object replaces the complete object,
resetting omitted flags to false and the omitted criterion to null. Omitted top-level fields are
preserved by PATCH; instructions: null clears the note. Saving never runs checks or matching.
Read matched invoices
relationships.invoice_match_count in agreement responses counts completed, non-deleted invoices
currently matched to the agreement. Read those invoices with Read access:
{ data, next_cursor } and standard invoice summaries. Use the returned cursor
with the same agreement, filters and ordering to continue. Invoice search, party/team filters,
categories, currencies, financial validity, issue/due date ranges and ordering are supported.
agreement_ids accepts up to 50 comma-separated agreement IDs and matches any of them. Each invoice
appears once, even when it matches several selected agreements. Unknown, deleted, or foreign agreement
IDs contribute no matches. Other filters combine with AND; deleted defaults to false. The same
filter is available on invoice metrics. Reading never recalculates matches when settings change.
Set invoice applicability
Read GET/v1/agreements/{id} to see applicability. It is part of the detail response; the list
endpoint returns summaries. These conditions describe which invoices the agreement can apply to.
They support reference fields (including order, buyer, seller, contract and project references)
and delivery fields (including name, address, city and country).
For example, this requires both a buyer reference containing SUPPORT and a Norwegian delivery:
match: "any" if either condition may match. Set applicability: null to remove the additional
conditions. Supplier/recipient selection and effective/expiration dates remain separate fields.
Values retain their whitespace. Existing conditions may exceed current write limits; unsupported
stored conditions return 409 rather than appearing as no conditions. Saving conditions starts no matching workflow.
The invoice list endpoint has a different purpose: browsing invoices. It also offers currency,
category, issue/due-date ranges, financial validity, agreement-match presence, teams and deletion
filters. Those query filters are not currently supported as stored agreement conditions.
Add amount and rate prices
"0.075" means 7.5%; price rates may exceed one.
Discount, surcharge and VAT fractions are between zero and one. The inactive price variant is
absent. Unknown descriptions, currency, units and other values remain null. Prices must be
nonnegative; invalid precision and reversed validity dates are rejected without rounding.
PATCH /price-items/{item_id} keeps the ID. Supplying price replaces its whole amount/rate
variant. Positions start at one, default to appending and can be edited independently. Removing a
price uses DELETE and returns 204; retained evidence from the prior value survives the deletion.
Agreement and price creation accept optional idempotency keys.
POST, PATCH and DELETE on the price collection accept plain arrays of 1–100 entries. Use an array
of one to create a single price. POST returns 201 and PATCH returns 200, each with a plain array
of affected prices in request order. DELETE returns 204. Each request succeeds or fails as a whole.
Updates preserve omitted fields; every supplied ID must be unique and belong to this agreement.
/price-items page without a search filter and send its
ETag in If-Match on collection PATCH/DELETE. Any limit or cursor is supported. It covers all
prices, even those on later pages. A search-filtered page or individual price has a different
validator. Collection PATCH returns the new collection ETag, so you can use it directly for the
next batch without another read.
An Idempotency-Key on POST protects the whole array from duplicate creation when retried.
Each semantic batch advances agreement freshness once and retains prior evidence for all changed
or deleted prices. Prices remain editable on archived agreements.
Upload and link a source
Use the direct upload protocol with a key that has Write access. After PUT succeeds, use the returneddocument_id to link that source:
download_url directly without your API bearer token. Linking requires uploaded, nonempty
bytes matching the registered size. It neither copies the file nor starts processing. Repeating the
same link succeeds; changing role or explicit position requires PATCH of the individual relationship.
Roles are terms, price_list, uncategorized, and excluded. Positions start at zero and default
to appending. DELETE removes the relationship and preserves the shared Document and retained evidence.
Import prices from a document
Link the price list as above, preferably with roleprice_list, then import it. The API extracts
its prices and appends them without a review step:
worksheets limits extraction to named sheets; instructions tells the
extraction which table or column holds the agreed prices. default_currency fills in amount prices
whose source states no currency. Extraction usually takes a few minutes. Cancel it with
the workflow run in workflow_run_id.
A completed import reports counts of its rows. Every extracted row has an outcome:
created: appended as a new price, after the existing ones.duplicate: the same product at the same price as an existing price or an earlier row, so nothing was added. Case and punctuation in text don’t matter; a different amount, unit, currency or validity makes a new price.invalid: breaks the price rules, for example a negative amount.
200 instead of
extracting it twice. A failed or cancelled import is retried by importing again. Every imported
price’s source names its import and the Document it came from, so you can always show where a price came from,
and the price table keeps the values as extracted after you edit the price. Imported Documents are
retained for that reason.
A failed import appends nothing. extraction_incomplete means the extraction could not read every
price with confidence: import again with instructions that say where the prices are, or with the
worksheets that hold them.
Edit safely, activate and archive
Individual agreement, price and document-link reads return anETag. Send that resource’s validator
in If-Match to protect an edit from concurrent changes:
412 precondition_failed. Read the current resource before reapplying
the edit. Without If-Match, supplied fields apply to the current locked state.
Set status through the agreement PATCH endpoint: active activates or reactivates, and archived
archives the agreement. Status and other edits apply atomically. Agreements, prices and source
relationships remain editable in every status. The resulting active agreement requires a nonblank
title; supplier and recipient selections may remain empty.
Repeating the current status without content changes succeeds without updating timestamps or version.
Saving and activating persist your changes without starting matching, processing, extraction,
compliance checks or renewal execution. Changes to coverage, invoice conditions, dates, renewal terms,
prices and relevant sources advance freshness; unchanged submissions,
equivalent decimals and reordered membership sets do not. Display ordering alone does not invalidate
checks. Existing results retain their prior evidence and are not automatically refreshed.
Lists use { data, next_cursor } with a default limit of 50 and maximum 100. Pass the same filters
and ordering on each page. Available ordering includes creation, title, effective date, expiration
date, first supplier, pending topics, alert progress and open alert impact; nulls sort last.
Every agreement carries an alert_summary with its alert counts, pending topics and impact per
status in your organization’s currency. has_alert_statuses=pending lists agreements with pending
alerts, and excluded_supplier_ids and excluded_tag_ids leave agreements out. valid_on tests the date interval independently of draft/active/archived status,
and absent bounds are open-ended. See the generated endpoint reference for the complete filter schema.
Delete an agreement
204. Use the agreement’s current ETag as If-Match to protect against a
concurrent edit. The agreement and its nested resources then return 404 and disappear from normal
app lists. Historical matches, assessments, prices, source relationships and evidence are retained;
shared Documents are preserved. Deletion returns 409 while agreement work is active, except API
classification and detail suggestions, compliance checks, topic reconciliation, topic proposals and
dismissal-context suggestions. There is no
restore operation; creating a new agreement requires a new idempotency key.
Price-list imports, indexing and compliance-check execution remain separate operations.
Saving settings, linking a source and reading matched invoices never start them.
Suggest a document role or agreement details
After uploading and linking PDFs, you can ask the API for suggestions with Write access:
Both return
202 with workflow_run_id, workflow_run_item_id, and a polling URL in Location.
Use workflow reads to follow progress and read the item result.
Classification works directly from a PDF, with a preview of at most ten pages. It does not need or
start extraction. Review the proposed terms, price_list, or excluded role and PATCH the
document relationship when you want to apply it. A skipped classification has role: null.
For detail suggestions, select 1–10 distinct attached PDFs whose document relationship role is
terms. Review and apply classification suggestions first, or set the role yourself. Other roles
return 400 validation_error.
You can request details immediately: the job uses current extracted Markdown when available and
original PDFs otherwise. The model reads both formats
together. Either extraction strategy is usable, including content whose verification was skipped
or failed. The job does not start extraction or indexing.
Selected source files may total at most 50 MiB. Extracted Markdown is limited to 500,000 combined
UTF-8 bytes, and each original PDF supplied directly is limited to 15 MB (15,000,000 bytes). Extract
larger PDFs first or select smaller files. Oversized model inputs fail without truncation; missing
files fail with source_unavailable. Both commands reject non-PDF MIME types with 415.
Selected artifacts are not pinned: replacement extraction or deletion can remove them before a queued job reads them. Submit a new suggestion request if that job fails with source_unavailable.
Detail results contain suggestions with title, dates, renewal terms, a smart matching criterion,
supplier and recipient. Unknown values remain null. Each identified party includes the extracted
name and organization_number under extracted, plus canonical id, name, and
organization_number under canonical. The API matches or creates parties through its shared
resolver. An organization number alone can match an existing party; creating one requires an
extracted name. A canonical mapping is null when the party cannot be resolved. Cancelling the job
prevents result publication but does not undo canonical parties already resolved.
Review the values, then PATCH only those you choose. Use canonical IDs in supplier_ids and
recipient_ids. Put a chosen criterion in matching_settings, retaining your intended
smart_matching_enabled value because nested objects replace the complete field. Use the current
agreement ETag in If-Match to protect against concurrent edits. The suggestion itself does not
change the agreement, attach parties, enable matching, or import prices.
Equivalent active requests reuse their run. Different active selections return 409 with that run’s
reference. Cancel via the workflow endpoint or wait for completion. Repeating a failed or cancelled
request creates a linked retry. Agreement edits remain available during suggestions, and later
document or extraction changes do not invalidate completed results.
Review suggested instruction edits
When someone dismisses an alert with a category or note, Watchdog reads the feedback and may propose small edits to the agreement’sinstructions, the context compliance checks read. Each such
dismissal starts an agreement_context_suggestions workflow run for the agreement; its item result
lists the suggestion_ids it created, which may be none. An organization’s runs execute one at a
time, in order. Find them with
GET /v1/workflow-runs?type=agreement_context_suggestions&resource_type=agreement&resource_id={id}.
anchor_text is the exact span it changes and occurs once in the
instructions; it is empty when operation is insert and the text is appended as a new paragraph.
replace swaps the anchor for proposed_text, insert adds it after the anchor, and delete
removes the anchor. evidence lists the 20 most recent dismissed alerts behind the suggestion with
their category and note, plus the total.
With Write access, POST …/context-suggestions/{suggestion_id}/accept applies the edit as an
ordinary agreement edit and returns the agreement with its new ETag; the version advances and the
same limits apply as for PATCH. POST …/reject leaves the instructions unchanged and keeps the edit
on record so it is not proposed again without new evidence. Both return 409 when the suggestion
was already reviewed, and accept returns 409 when the instructions no longer contain its anchor
exactly once. Editing the instructions deletes the pending suggestions the edit no longer fits.
Query matched-invoice counts and spend
UseGET /v1/invoices/metrics?agreement_ids={id} with Read access. It aggregates all matching
invoices without fetching individual rows or following pagination.
total_count for Matched invoices and total_amount_excluding_vat for Total
spend lifetime. Use the date-filtered response’s total_amount_excluding_vat for Total spend last
12 months. Credit notes reduce spend. Both dates are inclusive: calculate the start by subtracting
12 calendar months from the organization’s current local date, clamping leap day to February 28.
Lifetime includes future-dated and undated invoices; the bounded period excludes them.
Totals remain separate for each currency. A null currency group represents unknown currency, and a
null amount means at least one contributing amount is missing. Do not add different currencies or
treat unknown amounts as zero. An empty set returns zero counts and an empty currencies array.
The same search, party/team, currency, category, financial-validity and issue/due-date filters as
the invoice list are supported. Omit table filters to keep the headline cards at agreement
scope; include them if the cards should follow the table selection. financially_invalid_count
reports arithmetic validation, not compliance-check coverage. Checked ratios remain deferred.
My records and teams
Usemine=true or explicit team_ids to filter by shared team rules. See
My records and teams for matching rules,
empty results, errors, and pagination.