StabisoDocs

API reference

Purchase-orders

Purchase orders, receipts, matching of bills to orders and the matching tolerances.

Operation Summary Scope Idempotency-Key
GET /v1/documents/{document_id}/match Get Document Match read
POST /v1/documents/{document_id}/match Match Document draft
POST /v1/documents/{document_id}/match/approve Approve Document Variance approve
GET /v1/entities/{entity}/purchase-orders List Purchase Orders read
POST /v1/entities/{entity}/purchase-orders Create Purchase Order draft required
GET /v1/entities/{entity}/purchase-settings Get Purchase Settings read
PUT /v1/entities/{entity}/purchase-settings Set Purchase Settings admin
GET /v1/purchase-orders/{order} Get Purchase Order read
PATCH /v1/purchase-orders/{order} Update Purchase Order draft
POST /v1/purchase-orders/{order}/cancel Cancel Purchase Order draft required
POST /v1/purchase-orders/{order}/close Close Purchase Order draft required
GET /v1/purchase-orders/{order}/history Purchase Order History read
POST /v1/purchase-orders/{order}/receipts Receive Purchase Order draft required
POST /v1/purchase-orders/{order}/submit Submit Purchase Order draft

GET /v1/documents/{document_id}/match

Get Document Match

How a bill matches the purchase order its order reference names: per line, the order line, price and quantity variances (2-way or 3-way), the tolerance and whether the bill is blocked for payment. 404 when the bill was never matched.

Required scope read (admin implies every scope)
Operation id get_document_match_v1_documents__document_id__match_get

Parameters

In Name Type Required Description
path document_id string yes Document id (uuid) or number, e.g. INV-2026-000001.

Example request

curl "$ERP_URL/v1/documents/INV-2026-000001/match" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK MatchOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "document_number": "string",
  "order_reference": "string",
  "order_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "order_number": "string",
  "order_status": "string",
  "status": "matched",
  "payment_block": true,
  "review": "string",
  "problems": [
    "string"
  ],
  "problem_reasons": [
    {
      "words": "string",
      "code": "string",
      "details": null,
      "text": "string"
    }
  ],
  "tolerance": {},
  "price_variance": "string",
  "quantity_variance": "string",
  "overcharge": "string",
  "matched_by": {},
  "matched_at": "2026-09-21T09:30:00Z",
  "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "approval_status": "string",
  "approved_by": {},
  "approved_at": "2026-09-21T09:30:00Z",
  "approval_reason": "string",
  "held_approved_by": {},
  "held_approved_at": "2026-09-21T09:30:00Z",
  "lines": [
    {
      "document_line_no": 1,
      "description": "string",
      "quantity": "string",
      "unit_price": "string",
      "order_line_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "order_line_no": 1,
      "order_description": "string",
      "order_unit_price": "string",
      "ordered_quantity": "string",
      "received_quantity": "string",
      "paired_by": "string",
      "three_way": true,
      "excess_quantity": "string",
      "price_variance": "string",
      "quantity_variance": "string",
      "allowed": "string",
      "within_tolerance": true,
      "similarity": "string",
      "runner_up_line_no": 1,
      "problem": "string"
    }
  ]
}

POST /v1/documents/{document_id}/match

Match Document

Match a bill to its purchase order again (bills are matched when submitted). An approved variance stays approved. Safe to repeat.

Required scope draft (admin implies every scope)
Idempotency-Key not used
Operation id match_document_v1_documents__document_id__match_post

Parameters

In Name Type Required Description
path document_id string yes Document id (uuid) or number, e.g. INV-2026-000001.

Example request

curl -X POST "$ERP_URL/v1/documents/INV-2026-000001/match" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK MatchOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "document_number": "string",
  "order_reference": "string",
  "order_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "order_number": "string",
  "order_status": "string",
  "status": "matched",
  "payment_block": true,
  "review": "string",
  "problems": [
    "string"
  ],
  "problem_reasons": [
    {
      "words": "string",
      "code": "string",
      "details": null,
      "text": "string"
    }
  ],
  "tolerance": {},
  "price_variance": "string",
  "quantity_variance": "string",
  "overcharge": "string",
  "matched_by": {},
  "matched_at": "2026-09-21T09:30:00Z",
  "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "approval_status": "string",
  "approved_by": {},
  "approved_at": "2026-09-21T09:30:00Z",
  "approval_reason": "string",
  "held_approved_by": {},
  "held_approved_at": "2026-09-21T09:30:00Z",
  "lines": [
    {
      "document_line_no": 1,
      "description": "string",
      "quantity": "string",
      "unit_price": "string",
      "order_line_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "order_line_no": 1,
      "order_description": "string",
      "order_unit_price": "string",
      "ordered_quantity": "string",
      "received_quantity": "string",
      "paired_by": "string",
      "three_way": true,
      "excess_quantity": "string",
      "price_variance": "string",
      "quantity_variance": "string",
      "allowed": "string",
      "within_tolerance": true,
      "similarity": "string",
      "runner_up_line_no": 1,
      "problem": "string"
    }
  ]
}

POST /v1/documents/{document_id}/match/approve

Approve Document Variance

Approve a bill's purchase order variance with a reason, which releases its payment block (four eyes: not the person who entered or submitted the bill; agents never). The same as approving its request with POST /v1/approvals/{id}/approve.

Required scope approve (admin implies every scope)
Idempotency-Key not used
Operation id approve_document_variance_v1_documents__document_id__match_approve_post

Parameters

In Name Type Required Description
path document_id string yes Document id (uuid) or number, e.g. INV-2026-000001.

Request body

application/json (required): VarianceApproval

Field Type Required Description
reason string Why the variance is fine; required (refused with variance_reason_missing when empty). (max length 500; default "")

Example request

curl -X POST "$ERP_URL/v1/documents/INV-2026-000001/match/approve" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "reason": "Price increase agreed by phone with the supplier"
}'

Responses

Status Meaning Body
200 OK MatchOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "document_number": "string",
  "order_reference": "string",
  "order_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "order_number": "string",
  "order_status": "string",
  "status": "matched",
  "payment_block": true,
  "review": "string",
  "problems": [
    "string"
  ],
  "problem_reasons": [
    {
      "words": "string",
      "code": "string",
      "details": null,
      "text": "string"
    }
  ],
  "tolerance": {},
  "price_variance": "string",
  "quantity_variance": "string",
  "overcharge": "string",
  "matched_by": {},
  "matched_at": "2026-09-21T09:30:00Z",
  "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "approval_status": "string",
  "approved_by": {},
  "approved_at": "2026-09-21T09:30:00Z",
  "approval_reason": "string",
  "held_approved_by": {},
  "held_approved_at": "2026-09-21T09:30:00Z",
  "lines": [
    {
      "document_line_no": 1,
      "description": "string",
      "quantity": "string",
      "unit_price": "string",
      "order_line_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "order_line_no": 1,
      "order_description": "string",
      "order_unit_price": "string",
      "ordered_quantity": "string",
      "received_quantity": "string",
      "paired_by": "string",
      "three_way": true,
      "excess_quantity": "string",
      "price_variance": "string",
      "quantity_variance": "string",
      "allowed": "string",
      "within_tolerance": true,
      "similarity": "string",
      "runner_up_line_no": 1,
      "problem": "string"
    }
  ]
}

GET /v1/entities/{entity}/purchase-orders

List Purchase Orders

Purchase orders of an entity, newest first.

Required scope read (admin implies every scope)
Operation id list_purchase_orders_v1_entities__entity__purchase_orders_get

Parameters

In Name Type Required Description
path entity string yes Entity code, e.g. CH01 (GET /v1/entities).
query status array of "cancelled" | "closed" | "draft" | "open" | "partially_invoiced" | "partially_received" | "pending_approval" or null One or more statuses (repeat the parameter).
query vendor string or null Vendor code or id.
query start string (date) or null Order date from.
query end string (date) or null Order date to.
query q string or null Text in the number, buyer reference or vendor.
query review boolean Only orders with a paid bill that receipts recorded since would block. (default false)
query limit integer How many orders to return, newest first; at most 1000. (min 1; max 1000; default 100)

Example request

curl "$ERP_URL/v1/entities/CH01/purchase-orders" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK array of OrderOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

[
  {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "number": "string",
    "status": "string",
    "vendor": "string",
    "vendor_name": "string",
    "vendor_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "currency": "string",
    "order_date": "2026-09-21",
    "expected_date": "2026-09-21",
    "buyer_reference": "string",
    "net_total": "string",
    "created_at": "2026-09-21T09:30:00Z",
    "version": 1
  }
]

POST /v1/entities/{entity}/purchase-orders

Create Purchase Order

Create a draft purchase order for an active vendor (numbered at once). The payment terms and currency default to the vendor's. Nothing is posted to the ledger.

Required scope draft (admin implies every scope)
Idempotency-Key required
Operation id create_purchase_order_v1_entities__entity__purchase_orders_post

Parameters

In Name Type Required Description
path entity string yes Entity code, e.g. CH01 (GET /v1/entities).

Request body

application/json (required): OrderInput

Field Type Required Description
vendor string yes Vendor code or id; it must be active.
order_date string (date) or null Date of the order (ISO 8601, e.g. 2026-09-01); default today where the company is.
expected_date string (date) or null Expected delivery; not before the order date.
currency string or null Vendor's. (pattern ^[A-Z]{3}$)
buyer_reference string or null Your own reference for the order, e.g. a project or requisition number (up to 100 characters); searchable with q. (max length 100)
payment_terms_days integer or null Vendor's. (min 0; max 365)
delivery_address DeliveryAddress or null Where the goods are delivered; omit for the entity's own address.
notes string or null Free text kept on the order (up to 2000 characters). (max length 2000)
lines array of OrderLineInput yes The order lines, 1 to 500. Each is matched later against the bill's lines. (min items 1; max items 500)

Example request

curl -X POST "$ERP_URL/v1/entities/CH01/purchase-orders" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "buyer_reference": "REQ-2026-17",
  "expected_date": "2026-09-10",
  "lines": [
    {
      "account": "4000",
      "description": "Office chairs",
      "line_type": "goods",
      "quantity": "10",
      "unit_price": "100.00"
    }
  ],
  "order_date": "2026-09-01",
  "vendor": "V-BM"
}'

Responses

Status Meaning Body
201 Created OrderCard
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "number": "string",
  "status": "string",
  "vendor": "string",
  "vendor_name": "string",
  "vendor_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "currency": "string",
  "order_date": "2026-09-21",
  "expected_date": "2026-09-21",
  "buyer_reference": "string",
  "net_total": "string",
  "created_at": "2026-09-21T09:30:00Z",
  "version": 1,
  "payment_terms_days": 1,
  "delivery_address": {},
  "notes": "string",
  "cancel_reason": "string",
  "close_reason": "string",
  "closed_by": {},
  "closed_at": "2026-09-21T09:30:00Z",
  "created_by": {},
  "approved_by": {},
  "approved_at": "2026-09-21T09:30:00Z",
  "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "refusal": {
    "decided_by": {},
    "decided_at": "2026-09-21T09:30:00Z",
    "comment": "string"
  },
  "received_amount": "string",
  "invoiced_amount": "string",
  "lines": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "line_no": 1,
      "description": "string",
      "line_type": "string",
      "account": "string",
      "quantity": "string",
      "unit_price": "string",
      "net_amount": "string",
      "rate_type": "string",
      "tax_category": "string",
      "requires_receipt": true,
      "received_quantity": "string",
      "invoiced_quantity": "string",
      "invoiced_amount": "string",
      "closed_quantity": "0",
      "product_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "item": "string"
    }
  ],
  "receipts": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "number": "string",
      "status": "string",
      "receipt_date": "2026-09-21",
      "note": "string",
      "created_by": {},
      "created_at": "2026-09-21T09:30:00Z",
      "lines": [
        null
      ]
    }
  ],
  "bills": [
    {
      "document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "number": "string",
      "external_number": "string",
      "status": "string",
      "document_date": "2026-09-21",
      "currency": "string",
      "total": "string",
      "match_status": "string",
      "payment_block": true,
      "review": "string"
    }
  ]
}

GET /v1/entities/{entity}/purchase-settings

Get Purchase Settings

The entity's matching tolerances (default 2% and 5.00 per line, the stricter).

Required scope read (admin implies every scope)
Operation id get_purchase_settings_v1_entities__entity__purchase_settings_get

Parameters

In Name Type Required Description
path entity string yes Entity code, e.g. CH01 (GET /v1/entities).

Example request

curl "$ERP_URL/v1/entities/CH01/purchase-settings" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK SettingsOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "tolerance_percent": "string",
  "tolerance_amount": "string",
  "tolerance_bill_amount": "20.00",
  "entity": "string",
  "default": true,
  "updated_by": {},
  "updated_at": "2026-09-21T09:30:00Z"
}

PUT /v1/entities/{entity}/purchase-settings

Set Purchase Settings

Set the matching tolerances: a variance is allowed up to tolerance_percent of a line's expected amount and at most tolerance_amount (audited).

Required scope admin (admin implies every scope)
Idempotency-Key not used
Operation id set_purchase_settings_v1_entities__entity__purchase_settings_put

Parameters

In Name Type Required Description
path entity string yes Entity code, e.g. CH01 (GET /v1/entities).

Request body

application/json (required): SettingsInput

Field Type Required Description
tolerance_percent decimal string yes Variance allowed as a percent of the expected amount. (min 0; max 10)
tolerance_amount decimal string yes Variance allowed per line at most, in the order's currency. (min 0; max 1000)
tolerance_bill_amount decimal string Overcharge allowed per bill in total at most (the lines' variances added). (min 0; max 10000; default "20.00")

Example request

curl -X PUT "$ERP_URL/v1/entities/CH01/purchase-settings" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "tolerance_amount": "5.00",
  "tolerance_bill_amount": "20.00",
  "tolerance_percent": "2"
}'

Responses

Status Meaning Body
200 OK SettingsOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "tolerance_percent": "string",
  "tolerance_amount": "string",
  "tolerance_bill_amount": "20.00",
  "entity": "string",
  "default": true,
  "updated_by": {},
  "updated_at": "2026-09-21T09:30:00Z"
}

GET /v1/purchase-orders/{order}

Get Purchase Order

A purchase order by id or number: lines with ordered, received and invoiced quantities, receipts and the bills matched to it. The ETag names its version.

Required scope read (admin implies every scope)
Operation id get_purchase_order_v1_purchase_orders__order__get

Parameters

In Name Type Required Description
path order string yes Purchase order id (uuid) or number, e.g. PO-2026-000001.

Example request

curl "$ERP_URL/v1/purchase-orders/PO-2026-000001" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK OrderCard
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "number": "string",
  "status": "string",
  "vendor": "string",
  "vendor_name": "string",
  "vendor_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "currency": "string",
  "order_date": "2026-09-21",
  "expected_date": "2026-09-21",
  "buyer_reference": "string",
  "net_total": "string",
  "created_at": "2026-09-21T09:30:00Z",
  "version": 1,
  "payment_terms_days": 1,
  "delivery_address": {},
  "notes": "string",
  "cancel_reason": "string",
  "close_reason": "string",
  "closed_by": {},
  "closed_at": "2026-09-21T09:30:00Z",
  "created_by": {},
  "approved_by": {},
  "approved_at": "2026-09-21T09:30:00Z",
  "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "refusal": {
    "decided_by": {},
    "decided_at": "2026-09-21T09:30:00Z",
    "comment": "string"
  },
  "received_amount": "string",
  "invoiced_amount": "string",
  "lines": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "line_no": 1,
      "description": "string",
      "line_type": "string",
      "account": "string",
      "quantity": "string",
      "unit_price": "string",
      "net_amount": "string",
      "rate_type": "string",
      "tax_category": "string",
      "requires_receipt": true,
      "received_quantity": "string",
      "invoiced_quantity": "string",
      "invoiced_amount": "string",
      "closed_quantity": "0",
      "product_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "item": "string"
    }
  ],
  "receipts": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "number": "string",
      "status": "string",
      "receipt_date": "2026-09-21",
      "note": "string",
      "created_by": {},
      "created_at": "2026-09-21T09:30:00Z",
      "lines": [
        null
      ]
    }
  ],
  "bills": [
    {
      "document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "number": "string",
      "external_number": "string",
      "status": "string",
      "document_date": "2026-09-21",
      "currency": "string",
      "total": "string",
      "match_status": "string",
      "payment_block": true,
      "review": "string"
    }
  ]
}

PATCH /v1/purchase-orders/{order}

Update Purchase Order

Change a draft (lines replaces every line); 409 once submitted, 412 when If-Match names an older version.

Required scope draft (admin implies every scope)
Idempotency-Key not used
ETag / If-Match If-Match optional: a changed version answers 412
Response header ETag names the current version
Operation id update_purchase_order_v1_purchase_orders__order__patch

Parameters

In Name Type Required Description
path order string yes Purchase order id (uuid) or number, e.g. PO-2026-000001.
header If-Match string or null The ETag of the version you read; a changed purchase order answers 412. (max length 200)

Request body

application/json (required): OrderUpdate

Field Type Required Description
vendor string or null New vendor code or id; cannot be cleared.
order_date string (date) or null Date of the order (ISO 8601, e.g. 2026-09-01). Omit to keep the current value.
expected_date string (date) or null Expected delivery date (ISO 8601); not before order_date. Omit when unknown. Omit to keep the current value.
currency string or null ISO 4217 code of the order, e.g. CHF. Default: the vendor's currency. Omit to keep the current value. (pattern ^[A-Z]{3}$)
buyer_reference string or null Your own reference for the order, e.g. a project or requisition number (up to 100 characters); searchable with q. Omit to keep the current value. (max length 100)
payment_terms_days integer or null Payment terms in days, 0 to 365. Default: the vendor's. Omit to keep the current value. (min 0; max 365)
delivery_address DeliveryAddress or null Where the goods are delivered; omit for the entity's own address. Omit to keep the current value.
notes string or null Free text kept on the order (up to 2000 characters). Omit to keep the current value. (max length 2000)
lines array of OrderLineInput or null New lines; they replace every line. Omit to keep them. (min items 1; max items 500)

Example request

curl -X PATCH "$ERP_URL/v1/purchase-orders/PO-2026-000001" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H 'If-Match: "1"' \
  -H "Content-Type: application/json" \
  -d '{
  "expected_date": "2026-09-12",
  "notes": "Deliver to the reception desk."
}'

Responses

Status Meaning Body
200 OK OrderCard, ETag header
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
412 If-Match names a version that is no longer current (precondition_failed). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "number": "string",
  "status": "string",
  "vendor": "string",
  "vendor_name": "string",
  "vendor_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "currency": "string",
  "order_date": "2026-09-21",
  "expected_date": "2026-09-21",
  "buyer_reference": "string",
  "net_total": "string",
  "created_at": "2026-09-21T09:30:00Z",
  "version": 1,
  "payment_terms_days": 1,
  "delivery_address": {},
  "notes": "string",
  "cancel_reason": "string",
  "close_reason": "string",
  "closed_by": {},
  "closed_at": "2026-09-21T09:30:00Z",
  "created_by": {},
  "approved_by": {},
  "approved_at": "2026-09-21T09:30:00Z",
  "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "refusal": {
    "decided_by": {},
    "decided_at": "2026-09-21T09:30:00Z",
    "comment": "string"
  },
  "received_amount": "string",
  "invoiced_amount": "string",
  "lines": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "line_no": 1,
      "description": "string",
      "line_type": "string",
      "account": "string",
      "quantity": "string",
      "unit_price": "string",
      "net_amount": "string",
      "rate_type": "string",
      "tax_category": "string",
      "requires_receipt": true,
      "received_quantity": "string",
      "invoiced_quantity": "string",
      "invoiced_amount": "string",
      "closed_quantity": "0",
      "product_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "item": "string"
    }
  ],
  "receipts": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "number": "string",
      "status": "string",
      "receipt_date": "2026-09-21",
      "note": "string",
      "created_by": {},
      "created_at": "2026-09-21T09:30:00Z",
      "lines": [
        null
      ]
    }
  ],
  "bills": [
    {
      "document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "number": "string",
      "external_number": "string",
      "status": "string",
      "document_date": "2026-09-21",
      "currency": "string",
      "total": "string",
      "match_status": "string",
      "payment_block": true,
      "review": "string"
    }
  ]
}

POST /v1/purchase-orders/{order}/cancel

Cancel Purchase Order

Cancel an order on which nothing was received or invoiced (409 otherwise); a pending approval request is withdrawn. A cancelled order no longer changes.

Required scope draft (admin implies every scope)
Idempotency-Key required
ETag / If-Match If-Match optional: a changed version answers 412
Response header ETag names the current version
Operation id cancel_purchase_order_v1_purchase_orders__order__cancel_post

Parameters

In Name Type Required Description
path order string yes Purchase order id (uuid) or number, e.g. PO-2026-000001.
header If-Match string or null The ETag of the version you read; a changed purchase order answers 412. (max length 200)

Request body

application/json (required): CancelInput

Field Type Required Description
reason string yes Why; kept on the order. (min length 1; max length 500)

Example request

curl -X POST "$ERP_URL/v1/purchase-orders/PO-2026-000001/cancel" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H 'If-Match: "1"' \
  -H "Content-Type: application/json" \
  -d '{
  "reason": "Ordered from another supplier"
}'

Responses

Status Meaning Body
200 OK OrderCard, ETag header
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
412 If-Match names a version that is no longer current (precondition_failed). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "number": "string",
  "status": "string",
  "vendor": "string",
  "vendor_name": "string",
  "vendor_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "currency": "string",
  "order_date": "2026-09-21",
  "expected_date": "2026-09-21",
  "buyer_reference": "string",
  "net_total": "string",
  "created_at": "2026-09-21T09:30:00Z",
  "version": 1,
  "payment_terms_days": 1,
  "delivery_address": {},
  "notes": "string",
  "cancel_reason": "string",
  "close_reason": "string",
  "closed_by": {},
  "closed_at": "2026-09-21T09:30:00Z",
  "created_by": {},
  "approved_by": {},
  "approved_at": "2026-09-21T09:30:00Z",
  "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "refusal": {
    "decided_by": {},
    "decided_at": "2026-09-21T09:30:00Z",
    "comment": "string"
  },
  "received_amount": "string",
  "invoiced_amount": "string",
  "lines": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "line_no": 1,
      "description": "string",
      "line_type": "string",
      "account": "string",
      "quantity": "string",
      "unit_price": "string",
      "net_amount": "string",
      "rate_type": "string",
      "tax_category": "string",
      "requires_receipt": true,
      "received_quantity": "string",
      "invoiced_quantity": "string",
      "invoiced_amount": "string",
      "closed_quantity": "0",
      "product_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "item": "string"
    }
  ],
  "receipts": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "number": "string",
      "status": "string",
      "receipt_date": "2026-09-21",
      "note": "string",
      "created_by": {},
      "created_at": "2026-09-21T09:30:00Z",
      "lines": [
        null
      ]
    }
  ],
  "bills": [
    {
      "document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "number": "string",
      "external_number": "string",
      "status": "string",
      "document_date": "2026-09-21",
      "currency": "string",
      "total": "string",
      "match_status": "string",
      "payment_block": true,
      "review": "string"
    }
  ]
}

POST /v1/purchase-orders/{order}/close

Close Purchase Order

Close an approved order for the rest (short close) with a reason: what was received or invoiced stays, the rest of each line is closed (closed_quantity) and the order is closed. Receipts beyond what is left are refused, and a bill beyond it is a quantity variance that blocks its payment. 409 for a draft, cancelled or already closed order, or when nothing is left to close; 412 when If-Match names an older version.

Required scope draft (admin implies every scope)
Idempotency-Key required
ETag / If-Match If-Match optional: a changed version answers 412
Response header ETag names the current version
Operation id close_purchase_order_v1_purchase_orders__order__close_post

Parameters

In Name Type Required Description
path order string yes Purchase order id (uuid) or number, e.g. PO-2026-000001.
header If-Match string or null The ETag of the version you read; a changed purchase order answers 412. (max length 200)

Request body

application/json (required): CloseInput

Field Type Required Description
reason string yes Why; kept on the order. (min length 1; max length 500)

Example request

curl -X POST "$ERP_URL/v1/purchase-orders/PO-2026-000001/close" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H 'If-Match: "1"' \
  -H "Content-Type: application/json" \
  -d '{
  "reason": "The supplier cannot deliver the rest"
}'

Responses

Status Meaning Body
200 OK OrderCard, ETag header
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
412 If-Match names a version that is no longer current (precondition_failed). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "number": "string",
  "status": "string",
  "vendor": "string",
  "vendor_name": "string",
  "vendor_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "currency": "string",
  "order_date": "2026-09-21",
  "expected_date": "2026-09-21",
  "buyer_reference": "string",
  "net_total": "string",
  "created_at": "2026-09-21T09:30:00Z",
  "version": 1,
  "payment_terms_days": 1,
  "delivery_address": {},
  "notes": "string",
  "cancel_reason": "string",
  "close_reason": "string",
  "closed_by": {},
  "closed_at": "2026-09-21T09:30:00Z",
  "created_by": {},
  "approved_by": {},
  "approved_at": "2026-09-21T09:30:00Z",
  "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "refusal": {
    "decided_by": {},
    "decided_at": "2026-09-21T09:30:00Z",
    "comment": "string"
  },
  "received_amount": "string",
  "invoiced_amount": "string",
  "lines": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "line_no": 1,
      "description": "string",
      "line_type": "string",
      "account": "string",
      "quantity": "string",
      "unit_price": "string",
      "net_amount": "string",
      "rate_type": "string",
      "tax_category": "string",
      "requires_receipt": true,
      "received_quantity": "string",
      "invoiced_quantity": "string",
      "invoiced_amount": "string",
      "closed_quantity": "0",
      "product_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "item": "string"
    }
  ],
  "receipts": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "number": "string",
      "status": "string",
      "receipt_date": "2026-09-21",
      "note": "string",
      "created_by": {},
      "created_at": "2026-09-21T09:30:00Z",
      "lines": [
        null
      ]
    }
  ],
  "bills": [
    {
      "document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "number": "string",
      "external_number": "string",
      "status": "string",
      "document_date": "2026-09-21",
      "currency": "string",
      "total": "string",
      "match_status": "string",
      "payment_block": true,
      "review": "string"
    }
  ]
}

GET /v1/purchase-orders/{order}/history

Purchase Order History

The order's audit events: changes, submission, approval, receipts and status changes, oldest first.

Required scope read (admin implies every scope)
Operation id purchase_order_history_v1_purchase_orders__order__history_get

Parameters

In Name Type Required Description
path order string yes Purchase order id (uuid) or number, e.g. PO-2026-000001.

Example request

curl "$ERP_URL/v1/purchase-orders/PO-2026-000001/history" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK array of AuditEventOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

[
  {
    "id": 1,
    "at": "2026-09-21T09:30:00Z",
    "actor": {},
    "action": "string",
    "object_type": "string",
    "object_id": "string",
    "request_id": "string",
    "idempotency_key": "string",
    "data": {}
  }
]

POST /v1/purchase-orders/{order}/receipts

Receive Purchase Order

Record goods or services received per order line (a negative quantity corrects an earlier receipt). A line of a stock item, or any other line that needs a receipt and names an account, posts at receipt value against the GR/IR account (see goods received). Bills of the order blocked by a quantity variance are matched again once the receipt is posted, so a bill that arrived before the goods is released.

Required scope draft (admin implies every scope)
Idempotency-Key required
Operation id receive_purchase_order_v1_purchase_orders__order__receipts_post

Parameters

In Name Type Required Description
path order string yes Purchase order id (uuid) or number, e.g. PO-2026-000001.

Request body

application/json (required): ReceiptInput

Field Type Required Description
receipt_date string (date) or null Date the goods or services arrived (ISO 8601); default today where the company is.
note string or null Free text, e.g. the delivery note number (up to 500 characters). (max length 500)
warehouse string or null Code or id of the warehouse the stock items come into (or go back from); default the entity's default warehouse. Lines that are no stock items ignore it. (max length 40)
lines array of ReceiptLineInput yes What was received per order line, 1 to 500 lines. (min items 1; max items 500)

Example request

curl -X POST "$ERP_URL/v1/purchase-orders/PO-2026-000001/receipts" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "lines": [
    {
      "line_no": 1,
      "quantity": "6"
    }
  ],
  "note": "Delivery note 4711",
  "receipt_date": "2026-09-08"
}'

Responses

Status Meaning Body
201 Created OrderCard
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "number": "string",
  "status": "string",
  "vendor": "string",
  "vendor_name": "string",
  "vendor_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "currency": "string",
  "order_date": "2026-09-21",
  "expected_date": "2026-09-21",
  "buyer_reference": "string",
  "net_total": "string",
  "created_at": "2026-09-21T09:30:00Z",
  "version": 1,
  "payment_terms_days": 1,
  "delivery_address": {},
  "notes": "string",
  "cancel_reason": "string",
  "close_reason": "string",
  "closed_by": {},
  "closed_at": "2026-09-21T09:30:00Z",
  "created_by": {},
  "approved_by": {},
  "approved_at": "2026-09-21T09:30:00Z",
  "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "refusal": {
    "decided_by": {},
    "decided_at": "2026-09-21T09:30:00Z",
    "comment": "string"
  },
  "received_amount": "string",
  "invoiced_amount": "string",
  "lines": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "line_no": 1,
      "description": "string",
      "line_type": "string",
      "account": "string",
      "quantity": "string",
      "unit_price": "string",
      "net_amount": "string",
      "rate_type": "string",
      "tax_category": "string",
      "requires_receipt": true,
      "received_quantity": "string",
      "invoiced_quantity": "string",
      "invoiced_amount": "string",
      "closed_quantity": "0",
      "product_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "item": "string"
    }
  ],
  "receipts": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "number": "string",
      "status": "string",
      "receipt_date": "2026-09-21",
      "note": "string",
      "created_by": {},
      "created_at": "2026-09-21T09:30:00Z",
      "lines": [
        null
      ]
    }
  ],
  "bills": [
    {
      "document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "number": "string",
      "external_number": "string",
      "status": "string",
      "document_date": "2026-09-21",
      "currency": "string",
      "total": "string",
      "match_status": "string",
      "payment_block": true,
      "review": "string"
    }
  ]
}

POST /v1/purchase-orders/{order}/submit

Submit Purchase Order

Submit a draft for approval. By default a second person approves it (POST /v1/approvals/{id}/approve, action approve_purchase_order); when the approval policy allows it, a person with the approve scope approves it at once. Agents may submit, never approve.

Required scope draft (admin implies every scope)
Idempotency-Key not used
ETag / If-Match If-Match optional: a changed version answers 412
Response header ETag names the current version
Operation id submit_purchase_order_v1_purchase_orders__order__submit_post

Parameters

In Name Type Required Description
path order string yes Purchase order id (uuid) or number, e.g. PO-2026-000001.
header If-Match string or null The ETag of the version you read; a changed purchase order answers 412. (max length 200)

Example request

curl -X POST "$ERP_URL/v1/purchase-orders/PO-2026-000001/submit" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H 'If-Match: "1"'

Responses

Status Meaning Body
200 OK OrderCard, ETag header
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
404 The resource does not exist, or belongs to another organization (not_found). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
412 If-Match names a version that is no longer current (precondition_failed). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "number": "string",
  "status": "string",
  "vendor": "string",
  "vendor_name": "string",
  "vendor_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "currency": "string",
  "order_date": "2026-09-21",
  "expected_date": "2026-09-21",
  "buyer_reference": "string",
  "net_total": "string",
  "created_at": "2026-09-21T09:30:00Z",
  "version": 1,
  "payment_terms_days": 1,
  "delivery_address": {},
  "notes": "string",
  "cancel_reason": "string",
  "close_reason": "string",
  "closed_by": {},
  "closed_at": "2026-09-21T09:30:00Z",
  "created_by": {},
  "approved_by": {},
  "approved_at": "2026-09-21T09:30:00Z",
  "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "refusal": {
    "decided_by": {},
    "decided_at": "2026-09-21T09:30:00Z",
    "comment": "string"
  },
  "received_amount": "string",
  "invoiced_amount": "string",
  "lines": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "line_no": 1,
      "description": "string",
      "line_type": "string",
      "account": "string",
      "quantity": "string",
      "unit_price": "string",
      "net_amount": "string",
      "rate_type": "string",
      "tax_category": "string",
      "requires_receipt": true,
      "received_quantity": "string",
      "invoiced_quantity": "string",
      "invoiced_amount": "string",
      "closed_quantity": "0",
      "product_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "item": "string"
    }
  ],
  "receipts": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "number": "string",
      "status": "string",
      "receipt_date": "2026-09-21",
      "note": "string",
      "created_by": {},
      "created_at": "2026-09-21T09:30:00Z",
      "lines": [
        null
      ]
    }
  ],
  "bills": [
    {
      "document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "number": "string",
      "external_number": "string",
      "status": "string",
      "document_date": "2026-09-21",
      "currency": "string",
      "total": "string",
      "match_status": "string",
      "payment_block": true,
      "review": "string"
    }
  ]
}

Schemas

CancelInput

Field Type Required Description
reason string yes Why; kept on the order. (min length 1; max length 500)

CloseInput

Field Type Required Description
reason string yes Why; kept on the order. (min length 1; max length 500)

DeliveryAddress

Field Type Required Description
name string or null Name of the recipient at the address (up to 70 characters). (max length 70)
street string or null Street (up to 70 characters). (max length 70)
building_number string or null Building number (up to 16 characters). (max length 16)
postal_code string or null Postal code (up to 16 characters). (max length 16)
town string or null Town (up to 35 characters). (max length 35)
country string or null ISO 3166-1 alpha-2 country code in capitals, e.g. CH. (pattern ^[A-Z]{2}$)

MatchLineOut

Field Type Required Description
document_line_no integer yes Number of the bill line.
description string yes Description on the bill line.
quantity string yes Quantity billed.
unit_price string yes Unit price billed.
order_line_id string (uuid) or null yes Id of the order line paired with it; null when the line is not on the order.
order_line_no integer or null yes Number of that order line.
order_description string or null yes Description of that order line.
order_unit_price string or null yes Unit price on that order line.
ordered_quantity string or null yes Quantity ordered on that line.
received_quantity string or null yes Received on the order line now, on posted receipts.
paired_by string yes reference, description, price, single or none.
three_way boolean yes The order line needs a receipt (3-way match).
excess_quantity string yes Quantity billed beyond what was ordered (2-way) or received (3-way).
price_variance string yes Amount by which the price exceeds the order's, a decimal string.
quantity_variance string yes Amount of the excess quantity at the order price, a decimal string.
allowed string yes The variance the tolerances allow on the line.
within_tolerance boolean yes Whether the line's variance is within the tolerances.
similarity string or null How alike the descriptions are, 0 to 1 (pairing evidence).
runner_up_line_no integer or null The most similar other order line, if any.
problem string or null yes Why the line does not match; null when it does.

MatchOut

Field Type Required Description
document_id string (uuid) yes Id of the bill.
document_number string or null yes Number of the bill; null before it is posted.
order_reference string yes The order number the bill names (order_reference).
order_id string (uuid) or null yes Id of the purchase order found; null when none.
order_number string or null yes Number of that order.
order_status string or null yes Status of that order.
status "matched" | "unmatched" | "variance" yes matched, variance (payment is blocked until approved) or unmatched (the bill quotes an order that is none of its vendor's in its company: its posting waits for a second person).
payment_block boolean yes A variance nobody approved: the bill is not paid.
review string or null A paid bill that receipts recorded since would block: why.
problems array of string yes What is wrong, one sentence each; empty when matched.
problem_reasons array of Reason or null problems by code (purchaseMatch.problem) and the values they name, in the same order, for the screens to word; null for a match stored before they were kept.
tolerance object yes The tolerances applied: percent, amount and bill_amount.
price_variance string yes Total price variance of the lines, a decimal string.
quantity_variance string yes Total quantity variance of the lines, a decimal string.
overcharge string yes Higher prices, larger quantities, lines not ordered.
matched_by object yes Who matched the bill (type, id, name).
matched_at string (date-time) yes When it was matched (UTC).
approval_id string (uuid) or null yes Id of the approval request for the variance; null when none.
approval_status string or null yes pending, approved or rejected; null when none.
approved_by object or null yes Who approved the variance; null while not approved.
approved_at string (date-time) or null yes When it was approved (UTC).
approval_reason string or null yes The reason given with the approval.
held_approved_by object or null Of an unmatched bill: the second person who approved its posting, on the approval request that held it because of the unknown order (type, id, name); null while none has (not decided yet, or a bill posted before such bills were held).
held_approved_at string (date-time) or null When that approval was given (UTC); null when none.
lines array of MatchLineOut yes The match per bill line.

OrderBillOut

A bill matched to the order and how it matched.

Field Type Required Description
document_id string (uuid) yes Id of the bill.
number string or null yes Number of the bill; null before it is posted.
external_number string or null yes The vendor's own invoice number.
status string yes Status of the bill (draft, pending_approval, posted, rejected, void).
document_date string (date) yes Date of the bill.
currency string yes Currency of the bill.
total string yes Gross total of the bill, a decimal string.
match_status string yes matched, variance or unmatched.
payment_block boolean yes True while an unapproved variance blocks payment of the bill.
review string or null Paid, but receipts now disagree: why.

OrderCard

Field Type Required Description
id string (uuid) yes Id of the purchase order.
number string yes Order number, e.g. PO-2026-000001, from a sequence per entity and year.
status string yes draft, pending_approval, open, partially_received, partially_invoiced, closed (received and invoiced, or closed for the rest) or cancelled.
vendor string yes Vendor code.
vendor_name string yes Name of the vendor.
vendor_id string (uuid) yes Id of the vendor.
currency string yes ISO 4217 currency of the order.
order_date string (date) yes Date of the order.
expected_date string (date) or null yes Expected delivery date; null when none.
buyer_reference string or null yes Your own reference for the order; null when none.
net_total string yes Expected net total of all lines, a decimal string.
created_at string (date-time) yes When the order was created (UTC).
version integer yes Raised on every change; the ETag names it.
payment_terms_days integer yes Payment terms in days.
delivery_address object or null yes Delivery address; null when none.
notes string or null yes Free text on the order.
cancel_reason string or null yes Why the order was cancelled; null otherwise.
close_reason string or null Why the order was closed for the rest (short close); null otherwise.
closed_by object or null Who closed the order for the rest; null otherwise.
closed_at string (date-time) or null When it was closed for the rest (UTC); null otherwise.
created_by object yes Who created the order (type, id, name).
approved_by object or null yes Who approved the order; null until approved.
approved_at string (date-time) or null yes When it was approved (UTC).
approval_id string (uuid) or null yes The pending approval request, if any.
refusal OrderRefusal or null A draft whose last approval request was refused: who refused it, when and why. null otherwise (also once it is submitted again).
received_amount string yes Received quantities at the order prices.
invoiced_amount string yes Net amount invoiced so far on the bills of the order, less what posted credit notes of those bills credited.
lines array of OrderLineOut yes The lines with ordered, received and invoiced quantities.
receipts array of ReceiptOut yes The receipts, oldest first.
bills array of OrderBillOut yes

OrderInput

Field Type Required Description
vendor string yes Vendor code or id; it must be active.
order_date string (date) or null Date of the order (ISO 8601, e.g. 2026-09-01); default today where the company is.
expected_date string (date) or null Expected delivery; not before the order date.
currency string or null Vendor's. (pattern ^[A-Z]{3}$)
buyer_reference string or null Your own reference for the order, e.g. a project or requisition number (up to 100 characters); searchable with q. (max length 100)
payment_terms_days integer or null Vendor's. (min 0; max 365)
delivery_address DeliveryAddress or null Where the goods are delivered; omit for the entity's own address.
notes string or null Free text kept on the order (up to 2000 characters). (max length 2000)
lines array of OrderLineInput yes The order lines, 1 to 500. Each is matched later against the bill's lines. (min items 1; max items 500)

OrderLineInput

Field Type Required Description
description string yes What is ordered (1 to 500 characters); a bill line is paired with the order line by this text when it names no order line. (min length 1; max length 500)
line_type "goods" | "services" goods (default) or services. (default "goods")
account string or null Expense or asset account code.
quantity decimal string yes Ordered quantity, a decimal string above 0 with at most 6 decimals, e.g. 10. (greater than 0)
unit_price decimal string yes Expected net unit price. (min 0)
rate_type "exempt" | "parking" | "reduced" | "special" | "standard" | "super_reduced" | "zero" The tax code of the line. (default "standard")
tax_category string or null One of the categories of the rate (GET /v1/entities/{entity}/vat-rate-types), e.g. books: it chooses the rate where the rate type has several (France reduced: 5.5 % or 10 %) and names the kind of an exempt supply (insurance). Omit for none. (max length 200)
requires_receipt boolean or null Bills are matched 3-way against received quantities (default: goods yes, services no); otherwise 2-way against the ordered quantity.
item string or null A stock item of the order's entity the line buys (its product's code or id); the quantity is in the item's unit. Received goods then enter stock at the line's net price. Such a line is goods and needs a receipt. (max length 100)

OrderLineOut

Field Type Required Description
id string (uuid) yes Id of the order line.
line_no integer yes Line number, from 1.
description string yes What is ordered.
line_type string yes goods or services.
account string or null yes Account code.
quantity string yes Ordered quantity, a decimal string.
unit_price string yes Expected net unit price, a decimal string.
net_amount string yes Expected net amount.
rate_type string yes The tax code.
tax_category string or null yes Named tax category; null when the rate type decides.
requires_receipt boolean yes 3-way match against received quantities.
received_quantity string yes Quantity received so far, from the receipts (not those rejected).
invoiced_quantity string yes Quantity on the bills matched to the order (bills that count), less what posted credit notes of those bills credited of the line (credit note lines that name the bill line, credits_line).
invoiced_amount string yes Net amount on those bills less those credit notes, a decimal string.
closed_quantity string Quantity closed when the order was closed for the rest: no longer expected, neither received nor invoiced. (default "0")
product_id string (uuid) or null The stock item the line buys (its product's id): received goods enter stock; null for any other line.
item string or null Code of that stock item's product; null for any other line.

OrderOut

Field Type Required Description
id string (uuid) yes Id of the purchase order.
number string yes Order number, e.g. PO-2026-000001, from a sequence per entity and year.
status string yes draft, pending_approval, open, partially_received, partially_invoiced, closed (received and invoiced, or closed for the rest) or cancelled.
vendor string yes Vendor code.
vendor_name string yes Name of the vendor.
vendor_id string (uuid) yes Id of the vendor.
currency string yes ISO 4217 currency of the order.
order_date string (date) yes Date of the order.
expected_date string (date) or null yes Expected delivery date; null when none.
buyer_reference string or null yes Your own reference for the order; null when none.
net_total string yes Expected net total of all lines, a decimal string.
created_at string (date-time) yes When the order was created (UTC).
version integer yes Raised on every change; the ETag names it.

OrderRefusal

The approval a second person refused, which returned the order to draft.

Field Type Required Description
decided_by object yes Who refused it (type, id, name).
decided_at string (date-time) yes When it was refused (UTC).
comment string or null yes The reason given with the refusal; null when none.

OrderUpdate

Changes to a draft; omitted fields keep their value, lines replaces every line.

Field Type Required Description
vendor string or null New vendor code or id; cannot be cleared.
order_date string (date) or null Date of the order (ISO 8601, e.g. 2026-09-01). Omit to keep the current value.
expected_date string (date) or null Expected delivery date (ISO 8601); not before order_date. Omit when unknown. Omit to keep the current value.
currency string or null ISO 4217 code of the order, e.g. CHF. Default: the vendor's currency. Omit to keep the current value. (pattern ^[A-Z]{3}$)
buyer_reference string or null Your own reference for the order, e.g. a project or requisition number (up to 100 characters); searchable with q. Omit to keep the current value. (max length 100)
payment_terms_days integer or null Payment terms in days, 0 to 365. Default: the vendor's. Omit to keep the current value. (min 0; max 365)
delivery_address DeliveryAddress or null Where the goods are delivered; omit for the entity's own address. Omit to keep the current value.
notes string or null Free text kept on the order (up to 2000 characters). Omit to keep the current value. (max length 2000)
lines array of OrderLineInput or null New lines; they replace every line. Omit to keep them. (min items 1; max items 500)

ReceiptLineOut

Field Type Required Description
line_no integer yes Number of the order line.
description string yes Description of the order line.
quantity string yes Quantity received (negative for a correction).

ReceiptOut

Field Type Required Description
id string (uuid) yes Id of the receipt.
number string yes Receipt number.
status string yes posted; pending_approval while its posting waits for a second person (not counted by the 3-way match yet); rejected when the second person rejected it: it no longer counts as received.
receipt_date string (date) yes Date the goods or services arrived.
note string or null yes Free text, e.g. the delivery note number; null when none.
created_by object yes Who recorded it (type, id, name).
created_at string (date-time) yes When it was recorded (UTC).
lines array of ReceiptLineOut yes What was received per order line.

SettingsInput

Field Type Required Description
tolerance_percent decimal string yes Variance allowed as a percent of the expected amount. (min 0; max 10)
tolerance_amount decimal string yes Variance allowed per line at most, in the order's currency. (min 0; max 1000)
tolerance_bill_amount decimal string Overcharge allowed per bill in total at most (the lines' variances added). (min 0; max 10000; default "20.00")

SettingsOut

Field Type Required Description
tolerance_percent string yes Variance allowed as a percent of the expected amount.
tolerance_amount string yes Variance allowed per line at most, in the order's currency.
tolerance_bill_amount string Overcharge allowed per bill in total at most (the lines' variances added). (default "20.00")
entity string yes Entity code the tolerances belong to.
default boolean yes True while the entity uses the built-in tolerances.
updated_by object or null Who set them last; null while the built-in defaults apply.
updated_at string (date-time) or null When (UTC).

VarianceApproval

Field Type Required Description
reason string Why the variance is fine; required (refused with variance_reason_missing when empty). (max length 500; default "")
Stabiso, the Enterprise System of Record · generated from the code and its guides · release 20b7dd5b0c4d