StabisoDocs

API reference

Expenses

Expenses: a receipt's photo becomes an expense whose category, VAT, project and card fill in by themselves; the AI reviewer checks it against the company's expense policy, so a person sees only what it flags; it is booked as a bill and paid back in the next payment run. Company cards and their lines, matched to the receipts.

Operation Summary Scope Idempotency-Key
GET /v1/entities/{entity}/expense-policy Get the expense policy read
PUT /v1/entities/{entity}/expense-policy Set the expense policy admin
GET /v1/expense-card-lines List card payments read
POST /v1/expense-card-lines Add card payments admin required
GET /v1/expense-cards List cards read
POST /v1/expense-cards Add a company card admin required
PATCH /v1/expense-cards/{card_id} Change a card admin
POST /v1/expense-cards/{card_id}/statement Read a card statement admin required
GET /v1/expenses List expenses read
POST /v1/expenses Claim an expense without a receipt draft required
GET /v1/expenses-reimbursement Where you are paid back read
PUT /v1/expenses-reimbursement Set where you are paid back draft
POST /v1/expenses/receipts Claim an expense from a receipt's photo draft required
GET /v1/expenses/{expense_id} Get an expense read
PATCH /v1/expenses/{expense_id} Change your draft draft
GET /v1/expenses/{expense_id}/receipt Download an expense's receipt read
POST /v1/expenses/{expense_id}/submit Submit your expense draft
POST /v1/expenses/{expense_id}/withdraw Withdraw your draft draft

GET /v1/entities/{entity}/expense-policy

Get the expense policy

What the AI reviewer holds an expense for: the limit per receipt and per expense account, the oldest receipt taken and the amount above which a project is named. A company that has not set its own has the defaults (default true).

Required scope read (admin implies every scope)
Operation id get_expense_policy_v1_entities__entity__expense_policy_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/expense-policy" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK PolicyOut
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)

{
  "category_limits": {
    "6640": "80.00"
  },
  "max_age_days": 60,
  "receipt_limit": "500.00"
}

PUT /v1/entities/{entity}/expense-policy

Set the expense policy

Set the company's expense policy (administrators). Audited with what it was.

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

Parameters

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

Request body

application/json (required): PolicyUpdate

Field Type Required Description
receipt_limit decimal string or null A receipt above this, in the company's currency, waits for a person; null: no limit. (greater than 0)
category_limits map of decimal string Lower limits per expense account code, e.g. meals {"6640": "80.00"}.
max_age_days integer A receipt older than this waits for a person. (min 1; max 3660; default 90)
project_over decimal string or null Above this amount an expense names a project or waits; null: never asked. (min 0)

Example request

curl -X PUT "$ERP_URL/v1/entities/CH01/expense-policy" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "category_limits": {
    "6640": "80.00"
  },
  "max_age_days": 60,
  "receipt_limit": "500.00"
}'

Responses

Status Meaning Body
200 OK PolicyOut
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)

{
  "category_limits": {
    "6640": "80.00"
  },
  "max_age_days": 60,
  "receipt_limit": "500.00"
}

GET /v1/expense-card-lines

List card payments

The payments the card issuers listed, newest first, with the expense each was matched to; without_receipt lists those still waiting for their receipt.

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

Parameters

In Name Type Required Description
query entity string or null Only this company's (code or id).
query card string (uuid) or null Only this card's.
query without_receipt boolean Only those with no expense yet. (default false)
query mine boolean Only those of your own cards. (default false)
query limit integer How many, newest first. (min 1; max 5000; default 500)

Example request

curl "$ERP_URL/v1/expense-card-lines" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK array of CardLineOut
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
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",
    "card_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "last_four": "string",
    "holder_name": "string",
    "booked_on": "2026-09-21",
    "amount": "string",
    "currency": "string",
    "merchant": "string",
    "reference": "string",
    "expense_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "expense_number": "string"
  }
]

POST /v1/expense-card-lines

Add card payments

Payments as a card issuer lists them (a feed or an automation): each is matched by itself to its holder's receipt (the same amount within five days); one read before is skipped. An administrator's; needs an Idempotency-Key.

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

Request body

application/json (required): CardLinesInput

Field Type Required Description
lines array of CardLineInput yes The payments, as the issuer lists them. (min items 1; max items 5000)

Example request

curl -X POST "$ERP_URL/v1/expense-card-lines" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "lines": [
    {
      "amount": "84.50",
      "booked_on": "2026-10-21",
      "card": "3b0c8f4e-6a52-4f8e-9c1c-1f0d7a2b9e10",
      "merchant": "Restaurant Krone"
    }
  ]
}'

Responses

Status Meaning Body
201 Created CardLinesResult
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
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)

{
  "added": 1,
  "already_there": 1,
  "matched": 1,
  "lines": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "card_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "last_four": "string",
      "holder_name": "string",
      "booked_on": "2026-09-21",
      "amount": "string",
      "currency": "string",
      "merchant": "string",
      "reference": "string",
      "expense_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "expense_number": "string"
    }
  ]
}

GET /v1/expense-cards

List cards

The company cards, by holder, with the vendor each is booked to and how many of its payments have no receipt yet.

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

Parameters

In Name Type Required Description
query entity string or null Only this company's (code or id).

Example request

curl "$ERP_URL/v1/expense-cards" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK array of CardOut
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
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",
    "entity": "string",
    "holder": "string",
    "holder_name": "string",
    "last_four": "string",
    "currency": "string",
    "vendor": "string",
    "vendor_status": "string",
    "active": true,
    "open_lines": 1
  }
]

POST /v1/expense-cards

Add a company card

A card a person pays with for the company (administrators): its holder and last four digits. Its account with the issuer becomes a vendor of its own, activated through the controls; what is bought with the card is booked to it and kept out of payment runs. Needs an Idempotency-Key.

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

Request body

application/json (required): CardInput

Field Type Required Description
entity string or null Code (or id) of the company it is for, e.g. CH01; default: the organization's only company, else the one the person's last expense was for.
holder string yes Who holds it: the person's e-mail address or id (user:<id>).
last_four string yes The card number's last four digits. (pattern ^[0-9]{4}$)
currency string or null Its currency; default the company's. (pattern ^[A-Z]{3}$)

Example request

curl -X POST "$ERP_URL/v1/expense-cards" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "entity": "CH01",
  "holder": "anna@example.com",
  "last_four": "4821"
}'

Responses

Status Meaning Body
201 Created CardOut
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
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",
  "entity": "string",
  "holder": "string",
  "holder_name": "string",
  "last_four": "string",
  "currency": "string",
  "vendor": "string",
  "vendor_status": "string",
  "active": true,
  "open_lines": 1
}

PATCH /v1/expense-cards/{card_id}

Change a card

Stop using a card (active false) or use it again (administrators).

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

Parameters

In Name Type Required Description
path card_id string (uuid) yes Id of the card (GET /v1/expense-cards).

Request body

application/json (required): CardUpdate

Field Type Required Description
active boolean yes False: the card is no longer used.

Example request

curl -X PATCH "$ERP_URL/v1/expense-cards/{card_id}" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "active": false
}'

Responses

Status Meaning Body
200 OK CardOut
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",
  "entity": "string",
  "holder": "string",
  "holder_name": "string",
  "last_four": "string",
  "currency": "string",
  "vendor": "string",
  "vendor_status": "string",
  "active": true,
  "open_lines": 1
}

POST /v1/expense-cards/{card_id}/statement

Read a card statement

Add the payments of a card's statement file and match each to its receipt, as POST /v1/expense-card-lines. Needs an Idempotency-Key.

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

Parameters

In Name Type Required Description
path card_id string (uuid) yes Id of the card (GET /v1/expense-cards).

Request body

multipart/form-data (required): Body_read_expense_card_statement_v1_expense_cards__card_id__statement_post

Field Type Required Description
file string yes The issuer's statement: CSV or .xlsx with a date, amount and merchant.

Example request

curl -X POST "$ERP_URL/v1/expense-cards/{card_id}/statement" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F "file=@statement.xml"

Responses

Status Meaning Body
201 Created CardLinesResult
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)

{
  "added": 1,
  "already_there": 1,
  "matched": 1,
  "lines": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "card_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "last_four": "string",
      "holder_name": "string",
      "booked_on": "2026-09-21",
      "amount": "string",
      "currency": "string",
      "merchant": "string",
      "reference": "string",
      "expense_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "expense_number": "string"
    }
  ]
}

GET /v1/expenses

List expenses

The expenses, newest first, with what each is (receipt, category, VAT, project, card), what the AI reviewer found, the bill it is booked as and whether it is paid back.

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

Parameters

In Name Type Required Description
query entity string or null Only this company's (code or id).
query mine boolean Only the ones you paid. (default false)
query status "approved" | "draft" | "held" | "posted" | "rejected" | "withdrawn" or null Only those in this status.
query limit integer How many, newest first. (min 1; max 2000; default 200)

Example request

curl "$ERP_URL/v1/expenses" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK array of ExpenseOut
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
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",
    "entity": "string",
    "number": "string",
    "person": "string",
    "person_name": "string",
    "status": "approved",
    "source": "demo",
    "document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "merchant": "string",
    "merchant_country": "string",
    "receipt_date": "2026-09-21",
    "currency": "string",
    "total": "string",
    "vat_lines": [
      {
        "rate": "string",
        "net": "string",
        "vat": "string"
      }
    ],
    "account": "string",
    "account_name": "string",
    "dimensions": {},
    "description": "string",
    "paid_with": "card",
    "card": "string",
    "card_line_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "confidence": 1.5,
    "filled": {},
    "checks": [
      {
        "name": "string",
        "result": "pass",
        "detail": "string"
      }
    ],
    "review": "string",
    "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "bill_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "bill_number": "string",
    "paid_back": true,
    "problem": "string",
    "created_at": "2026-09-21T09:30:00Z",
    "submitted_at": "2026-09-21T09:30:00Z",
    "decided_by": {},
    "decided_at": "2026-09-21T09:30:00Z"
  }
]

POST /v1/expenses

Claim an expense without a receipt

A company card payment whose receipt is lost (card_line: its day, amount and merchant are taken from it), or a ticket with no file: your draft, with the category and project filled as for a receipt. Without a receipt the AI reviewer always holds it for a person. Needs an Idempotency-Key.

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

Request body

application/json (required): ExpenseInput

Field Type Required Description
entity string or null Code (or id) of the company it is for, e.g. CH01; default: the organization's only company, else the one the person's last expense was for.
card_line string (uuid) or null The company card payment it is (GET /v1/expense-card-lines): its day, amount and merchant are taken from it.
merchant string or null Who was paid. (max length 200)
receipt_date string (date) or null When; default today.
currency string or null ISO 4217; default the company's. (pattern ^[A-Z]{3}$)
total decimal string or null What was paid, VAT included; needed without a card line. (greater than 0)
description string or null What it was for, and why there is no receipt. (max length 500)

Example request

curl -X POST "$ERP_URL/v1/expenses" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "card_line": "3b0c8f4e-6a52-4f8e-9c1c-1f0d7a2b9e10",
  "description": "Lost"
}'

Responses

Status Meaning Body
201 Created ExpenseOut
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
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",
  "entity": "string",
  "number": "string",
  "person": "string",
  "person_name": "string",
  "status": "approved",
  "source": "demo",
  "document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "merchant": "string",
  "merchant_country": "string",
  "receipt_date": "2026-09-21",
  "currency": "string",
  "total": "string",
  "vat_lines": [
    {
      "rate": "string",
      "net": "string",
      "vat": "string"
    }
  ],
  "account": "string",
  "account_name": "string",
  "dimensions": {},
  "description": "string",
  "paid_with": "card",
  "card": "string",
  "card_line_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "confidence": 1.5,
  "filled": {},
  "checks": [
    {
      "name": "string",
      "result": "pass",
      "detail": "string"
    }
  ],
  "review": "string",
  "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "bill_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "bill_number": "string",
  "paid_back": true,
  "problem": "string",
  "created_at": "2026-09-21T09:30:00Z",
  "submitted_at": "2026-09-21T09:30:00Z",
  "decided_by": {},
  "decided_at": "2026-09-21T09:30:00Z"
}

GET /v1/expenses-reimbursement

Where you are paid back

The vendor you are paid back as and its IBAN; all null before your first expense or account.

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

Parameters

In Name Type Required Description
query entity string or null The company; default as above.

Example request

curl "$ERP_URL/v1/expenses-reimbursement" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK ReimbursementOut
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
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)

{
  "entity": "string",
  "vendor": "string",
  "vendor_status": "string",
  "iban": "string"
}

PUT /v1/expenses-reimbursement

Set where you are paid back

Your own bank account for expenses you paid: kept on the vendor you are paid back as (made the first time, numbered as every vendor, and activated by the AI reviewer or a second person). A new IBAN on an existing one is a change of bank details, which waits for a second person as any vendor's; payments wait meanwhile.

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

Request body

application/json (required): ReimbursementInput

Field Type Required Description
entity string or null Code (or id) of the company it is for, e.g. CH01; default: the organization's only company, else the one the person's last expense was for.
iban string yes Your own bank account's IBAN. (min length 15; max length 42)

Example request

curl -X PUT "$ERP_URL/v1/expenses-reimbursement" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "entity": "CH01",
  "iban": "CH93 0076 2011 6238 5295 7"
}'

Responses

Status Meaning Body
200 OK ReimbursementOut
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
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)

{
  "entity": "string",
  "vendor": "string",
  "vendor_status": "string",
  "iban": "string"
}

POST /v1/expenses/receipts

Claim an expense from a receipt's photo

Read a receipt and keep it as your draft expense, its fields filled by themselves: who was paid, when, the total and the VAT per rate from the receipt; the category (expense account) and project from what you booked before; your company card when the receipt or a card line says so (filled tells how each was found). Check it and submit it with POST /v1/expenses/{id}/submit, or send submit true. 409 (receipt_already_claimed) when the file is already an expense, 422 (not_a_receipt) for something else, 503 when no language model is configured. When no model answers in time the receipt is kept all the same, as your draft with nothing read from it (confidence null), to fill in. Needs an Idempotency-Key.

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

Request body

multipart/form-data (required): Body_claim_receipt_v1_expenses_receipts_post

Field Type Required Description
file string yes The receipt: a photo (JPEG, PNG, WebP) or a PDF; at most 20 MB.
entity string or null Code of the company it is for; default as POST /v1/expenses.
submit boolean Submit it at once, as read and filled, without a check. (default false)

Example request

curl -X POST "$ERP_URL/v1/expenses/receipts" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F "file=@statement.xml"

Responses

Status Meaning Body
201 Created ExpenseOut
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
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",
  "entity": "string",
  "number": "string",
  "person": "string",
  "person_name": "string",
  "status": "approved",
  "source": "demo",
  "document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "merchant": "string",
  "merchant_country": "string",
  "receipt_date": "2026-09-21",
  "currency": "string",
  "total": "string",
  "vat_lines": [
    {
      "rate": "string",
      "net": "string",
      "vat": "string"
    }
  ],
  "account": "string",
  "account_name": "string",
  "dimensions": {},
  "description": "string",
  "paid_with": "card",
  "card": "string",
  "card_line_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "confidence": 1.5,
  "filled": {},
  "checks": [
    {
      "name": "string",
      "result": "pass",
      "detail": "string"
    }
  ],
  "review": "string",
  "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "bill_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "bill_number": "string",
  "paid_back": true,
  "problem": "string",
  "created_at": "2026-09-21T09:30:00Z",
  "submitted_at": "2026-09-21T09:30:00Z",
  "decided_by": {},
  "decided_at": "2026-09-21T09:30:00Z"
}

GET /v1/expenses/{expense_id}

Get an expense

The expense with its checks, its bill and whether it is paid back.

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

Parameters

In Name Type Required Description
path expense_id string (uuid) yes Id of the expense (GET /v1/expenses).

Example request

curl "$ERP_URL/v1/expenses/{expense_id}" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK ExpenseOut
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",
  "entity": "string",
  "number": "string",
  "person": "string",
  "person_name": "string",
  "status": "approved",
  "source": "demo",
  "document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "merchant": "string",
  "merchant_country": "string",
  "receipt_date": "2026-09-21",
  "currency": "string",
  "total": "string",
  "vat_lines": [
    {
      "rate": "string",
      "net": "string",
      "vat": "string"
    }
  ],
  "account": "string",
  "account_name": "string",
  "dimensions": {},
  "description": "string",
  "paid_with": "card",
  "card": "string",
  "card_line_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "confidence": 1.5,
  "filled": {},
  "checks": [
    {
      "name": "string",
      "result": "pass",
      "detail": "string"
    }
  ],
  "review": "string",
  "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "bill_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "bill_number": "string",
  "paid_back": true,
  "problem": "string",
  "created_at": "2026-09-21T09:30:00Z",
  "submitted_at": "2026-09-21T09:30:00Z",
  "decided_by": {},
  "decided_at": "2026-09-21T09:30:00Z"
}

PATCH /v1/expenses/{expense_id}

Change your draft

Correct what was read or filled before you submit it; each field you change is marked as yours (filled). 403 (expense_not_yours) for another person's, 409 (expense_not_draft) once submitted.

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

Parameters

In Name Type Required Description
path expense_id string (uuid) yes Id of the expense (GET /v1/expenses).

Request body

application/json (required): ExpenseUpdate

Field Type Required Description
merchant string or null Who was paid. (max length 200)
merchant_country string or null ISO 3166 country of the merchant. (pattern ^[A-Z]{2}$)
receipt_date string (date) or null The receipt's date.
currency string or null ISO 4217. (pattern ^[A-Z]{3}$)
total decimal string or null Paid, VAT included. (greater than 0)
vat_lines array of VatLine-Input or null The VAT printed per rate. (max items 10)
account string or null The category: code of the expense account it is booked to.
dimensions map of string or null The project and other dimensions, {dimension code: value code}; an empty value takes one away.
description string or null What it was for. (max length 500)
paid_with "card" | "own" or null own (paid back to you) or card (your company card).
card string (uuid) or null Which of your company cards, when you hold several.

Example request

curl -X PATCH "$ERP_URL/v1/expenses/{expense_id}" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "account": "6640",
  "dimensions": {
    "project": "P-LYON"
  }
}'

Responses

Status Meaning Body
200 OK ExpenseOut
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",
  "entity": "string",
  "number": "string",
  "person": "string",
  "person_name": "string",
  "status": "approved",
  "source": "demo",
  "document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "merchant": "string",
  "merchant_country": "string",
  "receipt_date": "2026-09-21",
  "currency": "string",
  "total": "string",
  "vat_lines": [
    {
      "rate": "string",
      "net": "string",
      "vat": "string"
    }
  ],
  "account": "string",
  "account_name": "string",
  "dimensions": {},
  "description": "string",
  "paid_with": "card",
  "card": "string",
  "card_line_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "confidence": 1.5,
  "filled": {},
  "checks": [
    {
      "name": "string",
      "result": "pass",
      "detail": "string"
    }
  ],
  "review": "string",
  "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "bill_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "bill_number": "string",
  "paid_back": true,
  "problem": "string",
  "created_at": "2026-09-21T09:30:00Z",
  "submitted_at": "2026-09-21T09:30:00Z",
  "decided_by": {},
  "decided_at": "2026-09-21T09:30:00Z"
}

GET /v1/expenses/{expense_id}/receipt

Download an expense's receipt

The photo or PDF of the receipt, byte for byte (SHA-256 in X-Content-SHA256); 404 for an expense without one.

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

Parameters

In Name Type Required Description
path expense_id string (uuid) yes Id of the expense (GET /v1/expenses).
query download boolean true: as an attachment; default inline. (default false)

Example request

curl "$ERP_URL/v1/expenses/{expense_id}/receipt" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 The receipt as it was sent. application/pdf, application/xml, text/xml, image/png, image/jpeg, image/webp
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

POST /v1/expenses/{expense_id}/submit

Submit your expense

The AI reviewer checks it against the company's expense policy (receipt kept and readable, not claimed twice, not too old, within the limit, a project where asked, VAT that adds up, the card line): every check passes and it is approved and booked at once as a bill paid back in the next payment run (posted); one warns and it waits in Approvals for a person who may approve and did not pay it (held). In the four_eyes controls mode every expense waits for such a person. 422 (expense_incomplete) without a total, day or category.

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

Parameters

In Name Type Required Description
path expense_id string (uuid) yes Id of the expense (GET /v1/expenses).

Example request

curl -X POST "$ERP_URL/v1/expenses/{expense_id}/submit" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK ExpenseOut
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",
  "entity": "string",
  "number": "string",
  "person": "string",
  "person_name": "string",
  "status": "approved",
  "source": "demo",
  "document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "merchant": "string",
  "merchant_country": "string",
  "receipt_date": "2026-09-21",
  "currency": "string",
  "total": "string",
  "vat_lines": [
    {
      "rate": "string",
      "net": "string",
      "vat": "string"
    }
  ],
  "account": "string",
  "account_name": "string",
  "dimensions": {},
  "description": "string",
  "paid_with": "card",
  "card": "string",
  "card_line_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "confidence": 1.5,
  "filled": {},
  "checks": [
    {
      "name": "string",
      "result": "pass",
      "detail": "string"
    }
  ],
  "review": "string",
  "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "bill_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "bill_number": "string",
  "paid_back": true,
  "problem": "string",
  "created_at": "2026-09-21T09:30:00Z",
  "submitted_at": "2026-09-21T09:30:00Z",
  "decided_by": {},
  "decided_at": "2026-09-21T09:30:00Z"
}

POST /v1/expenses/{expense_id}/withdraw

Withdraw your draft

Withdraw a draft you will not claim; it is kept (withdrawn), never deleted, and its receipt may be claimed again.

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

Parameters

In Name Type Required Description
path expense_id string (uuid) yes Id of the expense (GET /v1/expenses).

Example request

curl -X POST "$ERP_URL/v1/expenses/{expense_id}/withdraw" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK ExpenseOut
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",
  "entity": "string",
  "number": "string",
  "person": "string",
  "person_name": "string",
  "status": "approved",
  "source": "demo",
  "document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "merchant": "string",
  "merchant_country": "string",
  "receipt_date": "2026-09-21",
  "currency": "string",
  "total": "string",
  "vat_lines": [
    {
      "rate": "string",
      "net": "string",
      "vat": "string"
    }
  ],
  "account": "string",
  "account_name": "string",
  "dimensions": {},
  "description": "string",
  "paid_with": "card",
  "card": "string",
  "card_line_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "confidence": 1.5,
  "filled": {},
  "checks": [
    {
      "name": "string",
      "result": "pass",
      "detail": "string"
    }
  ],
  "review": "string",
  "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "bill_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "bill_number": "string",
  "paid_back": true,
  "problem": "string",
  "created_at": "2026-09-21T09:30:00Z",
  "submitted_at": "2026-09-21T09:30:00Z",
  "decided_by": {},
  "decided_at": "2026-09-21T09:30:00Z"
}

Schemas

Body_claim_receipt_v1_expenses_receipts_post

Field Type Required Description
file string yes The receipt: a photo (JPEG, PNG, WebP) or a PDF; at most 20 MB.
entity string or null Code of the company it is for; default as POST /v1/expenses.
submit boolean Submit it at once, as read and filled, without a check. (default false)

Body_read_expense_card_statement_v1_expense_cards__card_id__statement_post

Field Type Required Description
file string yes The issuer's statement: CSV or .xlsx with a date, amount and merchant.

CardInput

Field Type Required Description
entity string or null Code (or id) of the company it is for, e.g. CH01; default: the organization's only company, else the one the person's last expense was for.
holder string yes Who holds it: the person's e-mail address or id (user:<id>).
last_four string yes The card number's last four digits. (pattern ^[0-9]{4}$)
currency string or null Its currency; default the company's. (pattern ^[A-Z]{3}$)

CardLineInput

Field Type Required Description
card string (uuid) yes The card (GET /v1/expense-cards).
booked_on string (date) yes The day the issuer lists.
amount decimal string yes Charged, in the card's currency (a refund is negative).
merchant string yes As the issuer lists it. (min length 1; max length 200)
reference string or null The issuer's id. (max length 200)

CardLineOut

Field Type Required Description
id string (uuid) yes Id of the line.
card_id string (uuid) yes The card.
last_four string yes Its last four digits.
holder_name string yes Its holder.
booked_on string (date) yes The day the issuer lists.
amount string yes Charged, in the card's currency.
currency string yes The card's currency.
merchant string yes As the issuer lists it.
reference string or null yes The issuer's id.
expense_id string (uuid) or null yes The expense it is; null: no receipt yet.
expense_number string or null yes That expense's number.

CardLinesInput

Field Type Required Description
lines array of CardLineInput yes The payments, as the issuer lists them. (min items 1; max items 5000)

CardLinesResult

Field Type Required Description
added integer yes Lines added.
already_there integer yes Lines a statement read before already had.
matched integer yes Lines matched to a receipt at once.
lines array of CardLineOut yes The lines added.

CardOut

Field Type Required Description
id string (uuid) yes Id of the card.
entity string yes Code of the company.
holder string yes Its holder (user:<id>).
holder_name string yes Their name.
last_four string yes The last four digits.
currency string yes Its currency.
vendor string yes The card's account with its issuer, as a vendor.
vendor_status string yes That vendor's status.
active boolean yes Still used.
open_lines integer yes Its payments without a receipt yet.

CardUpdate

Field Type Required Description
active boolean yes False: the card is no longer used.

ExpenseCheck

Field Type Required Description
name string yes The check: receipt, readable, duplicate, age, ...
result "pass" | "warn" yes warn holds it for a person.
detail string yes What the check found, in words.

ExpenseInput

An expense without a receipt file: a card payment whose receipt is lost, or one typed.

Field Type Required Description
entity string or null Code (or id) of the company it is for, e.g. CH01; default: the organization's only company, else the one the person's last expense was for.
card_line string (uuid) or null The company card payment it is (GET /v1/expense-card-lines): its day, amount and merchant are taken from it.
merchant string or null Who was paid. (max length 200)
receipt_date string (date) or null When; default today.
currency string or null ISO 4217; default the company's. (pattern ^[A-Z]{3}$)
total decimal string or null What was paid, VAT included; needed without a card line. (greater than 0)
description string or null What it was for, and why there is no receipt. (max length 500)

ExpenseOut

Field Type Required Description
id string (uuid) yes Id of the expense.
entity string yes Code of the company.
number string yes EX-2026-000001, gap-free per company and year.
person string yes Who paid (user:<id>).
person_name string yes Their name.
status "approved" | "draft" | "held" | "posted" | "rejected" | "withdrawn" yes draft (read, to check and submit), held (the AI reviewer or the controls wait for a person), approved (not booked yet: see problem), posted, rejected or withdrawn.
source "demo" | "no_receipt" | "receipt" yes receipt (read from a file), no_receipt (a card payment or ticket without a receipt file) or demo.
document_id string (uuid) or null yes The receipt's file (GET /v1/documents).
merchant string or null yes Who was paid.
merchant_country string or null yes ISO 3166 country of the merchant.
receipt_date string (date) or null yes The receipt's date.
currency string yes The receipt's currency.
total string or null yes Paid, VAT included, in the receipt's currency.
vat_lines array of VatLine-Output yes The VAT printed per rate.
account string or null yes The category: the expense account's code.
account_name string or null yes The account's name.
dimensions map of string yes The project and other dimensions.
description string or null yes What it was for.
paid_with "card" | "own" yes own or card.
card string or null yes The card's last four digits, when paid by card.
card_line_id string (uuid) or null yes The card payment it is matched to.
confidence number or null yes 0 to 1: how sure the reading is.
filled map of string yes How each field was filled: read (from the receipt), history (as your last ones), default, card (from the card line) or person.
checks array of ExpenseCheck yes What the AI reviewer checked, once submitted.
review string or null yes The reviewer's reasoning in words.
approval_id string (uuid) or null yes The approval request, once submitted.
bill_id string (uuid) or null yes The bill it is booked as, once posted.
bill_number string or null yes That bill's number.
paid_back boolean yes Paid back to the person (or, by card, settled by the card): nothing open.
problem string or null yes Why an approved expense is not booked yet.
created_at string (date-time) yes When the receipt came in (UTC).
submitted_at string (date-time) or null yes When it was submitted.
decided_by object or null yes Who approved or rejected it.
decided_at string (date-time) or null yes When.

ExpenseUpdate

What the person changes on a draft before submitting it (all optional).

Field Type Required Description
merchant string or null Who was paid. (max length 200)
merchant_country string or null ISO 3166 country of the merchant. (pattern ^[A-Z]{2}$)
receipt_date string (date) or null The receipt's date.
currency string or null ISO 4217. (pattern ^[A-Z]{3}$)
total decimal string or null Paid, VAT included. (greater than 0)
vat_lines array of VatLine-Input or null The VAT printed per rate. (max items 10)
account string or null The category: code of the expense account it is booked to.
dimensions map of string or null The project and other dimensions, {dimension code: value code}; an empty value takes one away.
description string or null What it was for. (max length 500)
paid_with "card" | "own" or null own (paid back to you) or card (your company card).
card string (uuid) or null Which of your company cards, when you hold several.

PolicyOut

Field Type Required Description
receipt_limit string or null A receipt above this, in the company's currency, waits for a person; null: no limit.
category_limits map of string Lower limits per expense account code, e.g. meals {"6640": "80.00"}.
max_age_days integer A receipt older than this waits for a person. (min 1; max 3660; default 90)
project_over string or null Above this amount an expense names a project or waits; null: never asked.
entity string yes Code of the company.
currency string yes The company's currency, of the limits.
default boolean yes True: the company has not set its own policy yet.

PolicyUpdate

Field Type Required Description
receipt_limit decimal string or null A receipt above this, in the company's currency, waits for a person; null: no limit. (greater than 0)
category_limits map of decimal string Lower limits per expense account code, e.g. meals {"6640": "80.00"}.
max_age_days integer A receipt older than this waits for a person. (min 1; max 3660; default 90)
project_over decimal string or null Above this amount an expense names a project or waits; null: never asked. (min 0)

ReimbursementInput

Field Type Required Description
entity string or null Code (or id) of the company it is for, e.g. CH01; default: the organization's only company, else the one the person's last expense was for.
iban string yes Your own bank account's IBAN. (min length 15; max length 42)

ReimbursementOut

Field Type Required Description
entity string yes Code of the company.
vendor string or null yes The vendor you are paid back as (V-00012); null before your first expense.
vendor_status string or null yes active, or draft until the AI reviewer or a person activates it.
iban string or null yes The account you are paid back to.

VatLine-Input

Field Type Required Description
rate decimal string yes The VAT rate printed, in percent (8.1). (min 0; max 100)
net decimal string yes The amount before VAT at this rate.
vat decimal string yes The VAT printed at this rate. (min 0)

VatLine-Output

Field Type Required Description
rate string yes The VAT rate printed, in percent (8.1).
net string yes The amount before VAT at this rate.
vat string yes The VAT printed at this rate.
Stabiso, the Enterprise System of Record · generated from the code and its guides · release 6f03a5e846b3