Skip to main content

Price Models

Extract a contract price clause into a stored model, read and edit it, confirm or exclude it, set its contract key, link amendments, and list every version.

A price model is a contract's price clause as one standard, evaluable structure. components are the prices, each with a formula over variable names, a unit such as ct/kWh or EUR/kW/a, a basis (energy, capacity or fixed) and an adjustment cycle (monthly, quarterly, semiannual, annual or fixed). variables are the numbers the formulas read: stated values with their evidence, and index variables bound to a series. A model also carries the printed contract number, customer, customer number and site, each with the passage that prints it.

Evidence is the backbone. Each stated value carries an evidence object with the quote, the document_id it was read from, and verified, which is true only when the quote occurs in the document text and prints the value. A paraphrased quote is replaced by the document line that prints the value (anchored: true), so the stored quote is always verbatim. A value that is not verified is treated as missing when prices are computed.

One model exists per contract document, and models that share a contract_key are versions of one contract. GET /v1/price-baseline/models/{id}/versions returns the whole chain, oldest first. The versions of a contract are the documents the Contracts app files under it, else the models sharing the contract key, else the chain linked by superseded_by. Later versions inherit what they do not redefine, so an amendment that changes one price needs only that price.

GET/v1/price-baseline/models

Response fields

data[].iduuidModel id.
data[].document_iduuidThe contract document the model was read from.
data[].contract_labelstringContract title or number as printed.
data[].statusstringdraft, confirmed, or excluded.
data[].currencystring | nullISO 4217 code the contract prices in.
data[].valid_fromstring | nullISO date the modelled price section applies from.
data[].contract_keystring | nullThe contract number, normalised.
data[].superseded_byuuid | nullThe model that replaces this one from its own valid_from.
data[].componentsstring[]Component keys.
data[].unverified_valuesintegerNon-index variables without a stated value or without a verified quote.
data[].index_seriesstring[]Series keys the model reads.
data[].updated_atdate-timeLast change.
POST/v1/price-baseline/models

Body fields

document_id*uuidContract document of the workspace.
use_opusbooleanUse the stronger model for contracts the default model leaves notes on.

cURL: Extract a price model

curl -X POST "https://api.talonic.com/v1/price-baseline/models" \
  -H "Authorization: Bearer $TALONIC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"document_id": "3f6c1d2e-8a41-4c57-9b0e-2d7a5c1e9f10", "use_opus": false}'

Response: 201 Draft model (excerpt)

{
  "id": "7b1f0a52-3c9d-4e08-a6d4-51c2e8f7b3a9",
  "document_id": "3f6c1d2e-8a41-4c57-9b0e-2d7a5c1e9f10",
  "contract_label": "Waermeliefervertrag Nr. 4711",
  "status": "draft",
  "contract_key": "4711",
  "valid_from": "2024-01-01",
  "superseded_by": null,
  "model": {
    "contract_label": "Waermeliefervertrag Nr. 4711",
    "currency": "EUR",
    "valid_from": "2024-01-01",
    "components": [
      {
        "key": "AP",
        "label": "Arbeitspreis",
        "unit": "ct/kWh",
        "basis": "energy",
        "formula": "AP0 * (0.4 + 0.6 * G / G0)",
        "adjustment": "quarterly"
      }
    ],
    "variables": [
      {
        "name": "AP0",
        "symbol": "AP0",
        "label": "Basis-Arbeitspreis",
        "kind": "base",
        "value": 6.42,
        "unit": "ct/kWh",
        "evidence": { "document_id": "3f6c1d2e-8a41-4c57-9b0e-2d7a5c1e9f10", "quote": "AP0 = 6,42 ct/kWh", "verified": true }
      }
    ],
    "referenced_documents": [],
    "notes": []
  },
  "created_at": "2025-03-12T10:02:41.000Z",
  "updated_at": "2025-03-12T10:02:41.000Z"
}

Extraction is conservative in three ways. A hand-set contract key survives re-extraction. An answer without price components never replaces a model that has them: the call answers 502 and the stored model stays. And every stated value is kept only when its quote occurs in the document and prints the value. A 502 means the extraction model is unavailable or returned no price components for a document that already has a model; the error is retryable.

GET/v1/price-baseline/models/{id}

Path parameters

id*uuidModel id.

Key response fields

statusstringdraft straight from extraction, confirmed once a person has checked it, excluded when the document sets no price.
extracted_withstring | nullModel id the extraction used.
contract_keystring | nullThe contract number; every model with the same key is a version of one contract.
model.contract_key_sourcestring | nullWhere the key came from: filename, contract, manual, or contracts.
model.variables[].kindstringbase, weight, constant, index, or quantity.
model.variables[].indexobjectFor index variables: series, description, reference (period_avg, prev_period_avg, prev_year_avg, prev2_year_avg, year_avg, month_before, custom), base_year, base_period, and mapped when an alias rule replaced a hand-entry series.
model.decisionsobjectHow a person chose to fill each open input, by input key.
PUT/v1/price-baseline/models/{id}

Body fields (all optional)

modelobjectA replacement model. It goes through the same sanitiser as an extraction, so an edited number without a quote that occurs in the contract and prints it is stored as unverified. A value may instead be quoted from another document of the workspace: set that document's id on the variable's evidence.
statusstringdraft, confirmed, or excluded. excluded keeps a document that sets no price (a withdrawn letter, a cover mail) out of the version chain.
contract_keystring | nullThe contract number this document belongs to, up to 64 characters. A non-empty value is stored as a hand-set key; null restores the key the file or the contract gives.
superseded_byuuid | nullModel of the later amendment or price sheet that replaces this one from its own valid_from; null unlinks. That model must state a valid_from on or after this model's, price in the same currency, and not lead back to this model (422).

cURL: Confirm a model and set its contract key

curl -X PUT "https://api.talonic.com/v1/price-baseline/models/7b1f0a52-3c9d-4e08-a6d4-51c2e8f7b3a9" \
  -H "Authorization: Bearer $TALONIC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status": "confirmed", "contract_key": "4711"}'
GET/v1/price-baseline/models/{id}/versions

Path parameters

id*uuidAny model of the contract.

cURL: Read the version chain

curl "https://api.talonic.com/v1/price-baseline/models/7b1f0a52-3c9d-4e08-a6d4-51c2e8f7b3a9/versions" \
  -H "Authorization: Bearer $TALONIC_API_KEY"
Editing re-runs the sanitiser. A number entered without a quote that occurs in the contract and prints it is stored, but marked unverified, and the prices that depend on it report missing_value until a verifying quote exists. To set a contract value together with its quote in one step, use POST /v1/price-baseline/models/{id}/values.

Frequently asked questions

Why was my edited number stored as unverified?+
An edited model goes through the same sanitiser as an extraction. A number is verified only when its quote occurs in the contract document and prints the value. Without such a quote the number is stored but treated as missing in price computation. Quote it from the contract, or from another document of the workspace by setting that document's id on the evidence.
How do two documents become versions of one contract?+
They share a contract_key, or the Contracts app files them under one contract, or one model names the other in superseded_by. The versions are ordered by valid_from. A later version inherits what it does not redefine, so an amendment needs to state only the prices it changes.
What does excluding a model do?+
Setting status to excluded keeps a document that sets no price, such as a withdrawn letter or a cover mail, out of the version chain. The document stays attached to the contract but never contributes components to the price computation.
What happens when extraction is run twice on the same document?+
The second run replaces the earlier draft for that document. A hand-set contract key survives, and an answer without price components never replaces a model that has them; that call answers 502 and leaves the stored model unchanged.