StabisoDocs

API reference

Setup

Legal entities, charts of accounts, fiscal years and periods.

Operation Summary Scope Idempotency-Key
GET /v1/charts List chart templates read
GET /v1/entities List Entities read
POST /v1/entities Create an entity admin required
GET /v1/entities/{entity} Get Entity read
PATCH /v1/entities/{entity} Update Entity admin
GET /v1/entities/{entity}/accounts List Accounts read
POST /v1/entities/{entity}/accounts Add an account admin
PATCH /v1/entities/{entity}/accounts/{code} Change an account admin
GET /v1/entities/{entity}/brand Read a company's brand read
PATCH /v1/entities/{entity}/brand Change a company's colours admin
GET /v1/entities/{entity}/brand/logo Download a company's logo read
POST /v1/entities/{entity}/brand/logo Upload a company's logo admin
DELETE /v1/entities/{entity}/brand/logo Remove a company's logo admin
GET /v1/entities/{entity}/fiscal-years List Fiscal Years read
POST /v1/entities/{entity}/fiscal-years Open a fiscal year admin
GET /v1/entities/{entity}/periods List Periods read
POST /v1/entities/{entity}/role-accounts Add Role Accounts admin required
GET /v1/industries List the industries a company can choose read
GET /v1/setup Tell whether the organization waits for its setup read
POST /v1/setup Set up the organization: Production, then Test admin
POST /v1/setup/companies Add a further company from the setup wizard's answers admin required
GET /v1/setup/options List what the setup wizard offers per country read

GET /v1/charts

List chart templates

The chart-of-accounts templates a new entity can start from: id is the value of chart in POST /v1/entities (e.g. ch_kmu, the Swiss KMU chart; ifrs_generic) and countries those whose standard chart it is (marked standard for country; provisioning starts an entity from it). POST /v1/entities without chart uses ifrs_generic.

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

Parameters

In Name Type Required Description
query country string or null ISO country code. (pattern ^[A-Z]{2}$)

Example request

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

Responses

Status Meaning Body
200 OK array of ChartTemplate
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": "string",
    "name": "string",
    "countries": [
      "string"
    ],
    "standard": false
  }
]

GET /v1/entities

List Entities

All legal entities of the organization, ordered by code. The code is what the other endpoints take as {entity}.

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

Example request

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

Responses

Status Meaning Body
200 OK array of EntityOut
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",
    "code": "string",
    "name": "string",
    "country": "string",
    "subdivision": "string",
    "functional_currency": "string",
    "fiscal_year_start_month": 1,
    "framework": "string",
    "vat_number": "string",
    "street": "string",
    "building_number": "string",
    "postal_code": "string",
    "town": "string",
    "contact_name": "string",
    "contact_phone": "string",
    "contact_email": "string",
    "electronic_address": "string",
    "electronic_address_scheme": "string",
    "posting_approval_limit": "string",
    "industry": "general",
    "time_zone": "string"
  }
]

POST /v1/entities

Create an entity

Create a legal entity with its chart of accounts, and optionally its fiscal years.

The accounts are copied from the chart template chart (see GET /v1/charts, which marks the country's standard chart); the template must carry every role the services need. fiscal_years lists the years whose periods are opened at once, on fiscal_calendar. Refused with 409 when the entity code is taken, in a test copy (company_in_test_copy: it takes its companies from Production; add the company there and make a new copy), and in an organization provisioned without a company, which waits for its administrator's setup (setup_not_done: POST /v1/setup makes the first company, then Test); 422 for an unknown chart or an invalid calendar, and 403 when the approval policy denies manage_accounts (always for agents).

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

Request body

application/json (required): EntityInput

Field Type Required Description
street string or null Street of the entity's address, at most 70 characters. (max length 70)
building_number string or null Building number of the address, at most 16 characters. (max length 16)
postal_code string or null Postal code of the address, at most 16 characters. (max length 16)
town string or null Town of the address, at most 35 characters. (max length 35)
contact_name string or null Seller contact (BT-41).
contact_phone string or null Seller contact phone (BT-42).
contact_email string or null Seller contact email (BT-43).
electronic_address string or null Seller electronic address (BT-34); defaults to contact_email.
electronic_address_scheme string or null EAS code, e.g. EM (email), 9930 (German VAT id), 0204.
code string yes Short unique code, 2 to 20 characters of A-Z, 0-9, _ and -, e.g. CH01; it names the entity in every URL. (pattern ^[A-Z0-9_-]{2,20}$)
name string yes Legal name, e.g. Demo AG.
country string yes ISO 3166-1 alpha-2 country code, e.g. CH or DE; decides the VAT rules. (pattern ^[A-Z]{2}$)
subdivision string or null ISO 3166-2 code of the state or canton, e.g. DE-BY; null when omitted. (pattern ^[A-Z]{2}-[A-Z0-9]{1,3}$)
functional_currency string or null ISO 4217 code of the currency the books are kept in, e.g. CHF. Cannot be changed later. Omitted: the currency of its country (422 entity_currency_needed where that is not known). (pattern ^[A-Z]{3}$)
fiscal_year_start_month integer Month the fiscal year starts, 1 to 12; default 1 (January). (min 1; max 12; default 1)
framework "ifrs" | "local" | "us_gaap" Accounting framework: ifrs (default), us_gaap or local. (default "ifrs")
vat_number string or null The entity's VAT number, e.g. CHE-123.456.788 MWST or DE123456788; null when omitted. For a Swiss or German entity its format is checked (422); it is printed on invoices and is required on them when the entity is VAT-registered.
chart string Chart template id (GET /v1/charts), e.g. ch_kmu; default ifrs_generic. GET /v1/charts?country= marks the country's standard chart, which the operator's provisioning uses. (default "ifrs_generic")
fiscal_years array of integer Years to open periods for.
fiscal_calendar FiscalCalendar or null Calendar for those years (default: twelve calendar months).
industry "ecommerce" | "general" | "hospitality" | "manufacturing" | "retail" | "services" | "trade" The company's industry (GET /v1/industries): general, hospitality, services, trade, retail, ecommerce or manufacturing. It puts the screens of the industry first in the app's menu and on its Home; it switches nothing off, and every operation works the same in every industry. Default general. (default "general")

Example request

curl -X POST "$ERP_URL/v1/entities" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "building_number": "10",
  "chart": "ch_kmu",
  "code": "CH02",
  "country": "CH",
  "fiscal_years": [
    2026
  ],
  "functional_currency": "CHF",
  "name": "Demo Services AG",
  "postal_code": "8001",
  "street": "Bahnhofstrasse",
  "town": "Zurich",
  "vat_number": "CHE-123.456.788 MWST"
}'

Responses

Status Meaning Body
201 Created EntityOut
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",
  "code": "string",
  "name": "string",
  "country": "string",
  "subdivision": "string",
  "functional_currency": "string",
  "fiscal_year_start_month": 1,
  "framework": "string",
  "vat_number": "string",
  "street": "string",
  "building_number": "string",
  "postal_code": "string",
  "town": "string",
  "contact_name": "string",
  "contact_phone": "string",
  "contact_email": "string",
  "electronic_address": "string",
  "electronic_address_scheme": "string",
  "posting_approval_limit": "string",
  "industry": "general",
  "time_zone": "string"
}

GET /v1/entities/{entity}

Get Entity

One entity with its legal data, address, contact and e-invoicing address, its posting approval limit and a request to raise or remove it that waits (posting_limit_request). The path takes the entity code or its id.

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

Responses

Status Meaning Body
200 OK EntityDetailOut
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",
  "code": "string",
  "name": "string",
  "country": "string",
  "subdivision": "string",
  "functional_currency": "string",
  "fiscal_year_start_month": 1,
  "framework": "string",
  "vat_number": "string",
  "street": "string",
  "building_number": "string",
  "postal_code": "string",
  "town": "string",
  "contact_name": "string",
  "contact_phone": "string",
  "contact_email": "string",
  "electronic_address": "string",
  "electronic_address_scheme": "string",
  "posting_approval_limit": "string",
  "industry": "general",
  "posting_limit_request": {
    "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "current": "string",
    "proposed": "string",
    "requested_by": {},
    "requested_at": "2026-09-21T09:30:00Z"
  },
  "time_zone": "string"
}

PATCH /v1/entities/{entity}

Update Entity

Change an entity's name, VAT number, address, contact or e-invoicing address (the seller on XRechnung). Only the fields sent with a value change; null or omitted leaves a field as it is. Code, country, currency and framework cannot be changed. A Swiss or German VAT number must have the format of a UID or USt-IdNr (422). Refused with 403 when the approval policy denies the action manage_accounts. Audited as entity.update.

posting_approval_limit is the exception: null removes it. Only a person with the admin scope changes it; a lower limit applies at once, while raising or removing it waits for a second person (policy action change_posting_limit): the answer then keeps the old limit and names the request in posting_limit_request, approved under Approvals.

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

Parameters

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

Request body

application/json (required): EntityUpdate

Field Type Required Description
street string or null Street of the address, at most 70 characters; omit or null to keep it. (max length 70)
building_number string or null Building number, at most 16 characters; omit or null to keep it. (max length 16)
postal_code string or null Postal code, at most 16 characters; omit or null to keep it. (max length 16)
town string or null Town, at most 35 characters; omit or null to keep it. (max length 35)
contact_name string or null Seller contact (BT-41).
contact_phone string or null Seller contact phone (BT-42).
contact_email string or null Seller contact email (BT-43).
electronic_address string or null Seller electronic address (BT-34); defaults to contact_email.
electronic_address_scheme string or null EAS code, e.g. EM (email), 9930 (German VAT id), 0204.
name string or null New legal name; omit or null to keep it.
vat_number string or null New VAT number (format checked for a Swiss or German entity, 422); omit or null to keep it.
industry "ecommerce" | "general" | "hospitality" | "manufacturing" | "retail" | "services" | "trade" or null The company's industry (GET /v1/industries): general, hospitality, services, trade, retail, ecommerce or manufacturing. It puts the screens of the industry first in the app's menu and on its Home; it switches nothing off, and every operation works the same in every industry. Omit or null to keep it; audited with the other changes.
posting_approval_limit decimal string or null The posting approval limit in the functional currency: whatever a person posts (a manual journal, a bill, an invoice, a payment, a refund, a VAT settlement, a revaluation, a depreciation run) whose functional amount is above it waits for a second person, and so does its reversal. A new company starts at about CHF 100,000 in its currency as a round figure (100000.00 CHF, EUR, USD, GBP or CAD, 1000000.00 SEK, 15000000 JPY). Omit it to keep the limit; null removes it (a one-person company). Only a person with the admin scope changes it (403 posting_limit_admin_only). A lower limit applies at once; raising or removing it waits for a second person (policy action change_posting_limit): the answer keeps the old limit and names the request in posting_limit_request (409 posting_limit_change_waiting while one waits, until it is decided or its requester withdraws it with POST /v1/approvals/{approval_id}/withdraw). A person alone in the organization (one active person, nobody else disabled or demoted in the last 30 days) changes it at once. Audited as entity.posting_limit with the value before and after (and alone when it applied so). (greater than 0)

Example request

curl -X PATCH "$ERP_URL/v1/entities/CH01" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "building_number": "5",
  "street": "Seestrasse",
  "town": "Zurich"
}'

Responses

Status Meaning Body
200 OK EntityDetailOut
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",
  "code": "string",
  "name": "string",
  "country": "string",
  "subdivision": "string",
  "functional_currency": "string",
  "fiscal_year_start_month": 1,
  "framework": "string",
  "vat_number": "string",
  "street": "string",
  "building_number": "string",
  "postal_code": "string",
  "town": "string",
  "contact_name": "string",
  "contact_phone": "string",
  "contact_email": "string",
  "electronic_address": "string",
  "electronic_address_scheme": "string",
  "posting_approval_limit": "string",
  "industry": "general",
  "posting_limit_request": {
    "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "current": "string",
    "proposed": "string",
    "requested_by": {},
    "requested_at": "2026-09-21T09:30:00Z"
  },
  "time_zone": "string"
}

GET /v1/entities/{entity}/accounts

List Accounts

The entity's chart of accounts ordered by code, inactive accounts included (active). Control accounts (is_control) take postings only from their subledger.

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

Parameters

In Name Type Required Description
path entity string yes Entity code, e.g. CH01 (GET /v1/entities).
query q string or null Keep accounts whose code starts with this text or whose name, or a translation of it, contains it (case-insensitive); omit for the whole chart.

Example request

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

Responses

Status Meaning Body
200 OK array of AccountOut
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",
    "code": "string",
    "name": "string",
    "type": "string",
    "report_line": "string",
    "role": "string",
    "is_control": true,
    "currency": "string",
    "active": true,
    "vat_recovery_percent": "string"
  }
]

POST /v1/entities/{entity}/accounts

Add an account

Add an account to the entity's chart. Refused with 409 when the code is taken, with 422 when the number is not one word, the name is empty or more than one line, or the report line is unknown or holds another type of account (pl.opex.other holds expense accounts, never revenue), and with 403 when the approval policy denies the action manage_accounts (always for agents). An account with a role is the account the services use for that purpose, e.g. bank. Audited as account.create.

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

Parameters

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

Request body

application/json (required): AccountInput

Field Type Required Description
code string yes Account number, unique in the entity, e.g. 6510.
name string yes Account name, e.g. Telefon und Internet.
type "asset" | "equity" | "expense" | "liability" | "revenue" yes asset, liability, equity, revenue or expense; decides the normal balance side and which report it appears in.
report_line string yes Where the account appears in the statements, as a dotted key such as pl.opex.other, pl.revenue or bs.assets.current.cash. Use a line the chart already uses for the same type: each line holds one type of account (422 otherwise).
role string or null The purpose the services use the account for, e.g. bank, ar_control, vat_input, default_expense; null for an ordinary account.
control boolean True for a control account, which takes postings only from its subledger (receivables, payables, bank, fixed assets); default false. (default false)
currency string or null ISO 4217 code when the account only accepts one currency, e.g. EUR; null (default) accepts any.
vat_recovery_percent decimal string or null How much of the input VAT of a bill line booked to the account the company may deduct, in percent (0 to 100), when the line states none (ADR-0079): e.g. 0 on an account for gifts whose VAT the law excludes, 50 for a car used half privately. The rest of the VAT is booked as part of the cost on this account. Null: all of it. (min 0; max 100)

Example request

curl -X POST "$ERP_URL/v1/entities/CH01/accounts" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "code": "6510",
  "name": "Telefon und Internet",
  "report_line": "pl.opex.other",
  "type": "expense"
}'

Responses

Status Meaning Body
201 Created AccountOut
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",
  "code": "string",
  "name": "string",
  "type": "string",
  "report_line": "string",
  "role": "string",
  "is_control": true,
  "currency": "string",
  "active": true,
  "vat_recovery_percent": "string"
}

PATCH /v1/entities/{entity}/accounts/{code}

Change an account

Rename an account, give it a role, take it away, change its statement line or deactivate it. Only the fields sent change; role: null takes the role away. A chart is the customer's own (imported), so an existing account must be able to take the role a service looks for.

A role says which account a service posts to, so who holds it is controlled. The role must be one the services know and fit the account's type (422); only one account of the entity holds it (409); a control role (bank, ar_control, ap_control, fixed_asset_cost, accumulated_depreciation, annual_result, ...) is refused (409) on an account that already has postings from outside its subledger. A change to or from a control or required role is a request for a second person (the approval policy's change_required_account_role, default require_approval): the answer is 202 with status pending_approval and the approval_id, and the account changes when another person approves it (POST /v1/approvals/{approval_id}/approve). The role of an ordinary account changes at once; a rename alone always does. An account cannot be deactivated (409, naming why) while it holds a role, is a control account, carries a balance (a P&L account: a result in a fiscal year not closed to zero), is named by unfinished work (an entry, invoice, bill, purchase order, payment or recurring invoice), or while a fixed asset, product, subscription, contract, party, bank account or setting posts to it. The report line must be one that holds the account's type (422). The number, type and currency are fixed. Every change is audited with the previous value (account.role.change, account.update); a request, a rejection and an approval are audited too. Repeating a change that has been applied changes nothing. Refused with 403 when the policy denies manage_accounts (always for agents), 404 for an unknown account, 409 for the refusals above and for a second pending request on the account.

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

Parameters

In Name Type Required Description
path entity string yes Entity code, e.g. CH01 (GET /v1/entities).
path code string yes Account code in the entity's chart, e.g. 6510.

Request body

application/json (required): AccountUpdate

Field Type Required Description
role string or null The purpose the services use the account for, e.g. retained_earnings or deferred_tax_asset (GET /v1/entities/{entity}/accounts shows the roles in use). Send null to take the role away; omit to leave it. The role must be one the services know and fit the account's type (422), and no other account of the entity may hold it (409). A control role is refused (409) on an account that already has postings from outside its subledger. Changing a control or required role needs a second person: the answer is 202 with a pending approval. (max length 64; pattern ^[a-z][a-z0-9_]*$)
name string or null A new name for the account, e.g. Telefon und Internet; the number, type and postings stay as they are. Omit to leave it. (min length 1; max length 200)
report_line string or null The statement line the account is grouped under, e.g. pl.opex.other; each line holds one type of account, so an expense account goes on an expense line, never on a revenue or balance-sheet one (422). Omit to leave it. (max length 120; pattern `^(bs
active boolean or null False stops postings to the account, true allows them again. Refused (409, naming why) while the account holds a role, is a control account, carries a balance (a P&L account: a result in a year not closed to zero), is named by unfinished work (an entry, invoice, bill, order, payment or recurring invoice), or while an asset, product, subscription, contract, party or setting posts to it. Omit to leave it.
vat_recovery_percent decimal string or null How much of the input VAT of a bill line booked to the account the company may deduct, in percent (0 to 100), when the line states none (ADR-0079): e.g. 0 on an account for gifts whose VAT the law excludes, 50 for a car used half privately. The rest of the VAT is booked as part of the cost on this account. Null: all of it. Send null to take it away; omit to leave it. Bills already entered keep theirs. (min 0; max 100)
reason string or null Why; kept in the audit trail and shown to the second person who decides a change of a control or required role. (min length 3; max length 500)

Example request

curl -X PATCH "$ERP_URL/v1/entities/CH01/accounts/6510" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "reason": "Customer chart: 2979 holds the year'\''s result",
  "role": "annual_result"
}'

Responses

Status Meaning Body
200 OK AccountChange
202 Waits for a second person. AccountChange
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)

{
  "account": {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "code": "string",
    "name": "string",
    "type": "string",
    "report_line": "string",
    "role": "string",
    "is_control": true,
    "currency": "string",
    "active": true,
    "vat_recovery_percent": "string"
  },
  "status": "applied",
  "changed": [
    "string"
  ],
  "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}

GET /v1/entities/{entity}/brand

Read a company's brand

The company's logo, brand and accent colours and the theme of the app, with the contrast of the colours in use against white. A company that set nothing has the product's look: no logo, the deep teal, the light theme.

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

Responses

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

{
  "entity": "string",
  "theme": "dark",
  "colour": "string",
  "accent": "string",
  "effective_colour": "string",
  "effective_accent": "string",
  "logo": {
    "url": "string",
    "width": 1,
    "height": 1,
    "filename": "string",
    "sha256": "string"
  },
  "checks": [
    {
      "name": "accent",
      "colour": "string",
      "ratio": 1.5,
      "minimum": 1.5,
      "passes": true
    }
  ],
  "updated_at": "2026-09-21T09:30:00Z",
  "updated_by": "string"
}

PATCH /v1/entities/{entity}/brand

Change a company's colours

Change the theme (light, dark, system), the brand colour or the accent colour; only the fields sent change, and null sets a colour back to the default. The brand colour is the app's buttons and links and the title of every invoice, quote and reminder: it must reach 4.5:1 against white (422 brand_colour_contrast, with the ratio). The accent colour draws the rules of the documents and the band of the e-mails: 3:1 (422 brand_accent_contrast). 422 brand_colour for what is not a colour. Audited as brand.update.

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

Parameters

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

Request body

application/json (required): BrandUpdate

Field Type Required Description
theme "dark" | "light" | "system" or null light, dark or system.
colour string or null #rrggbb (or #rgb); at least 4.5:1 against white. null: the default. (max length 7)
accent string or null #rrggbb (or #rgb); at least 3:1 against white. null: the brand colour. (max length 7)

Example request

curl -X PATCH "$ERP_URL/v1/entities/CH01/brand" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "colour": "#1d4ed8",
  "theme": "system"
}'

Responses

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

{
  "entity": "string",
  "theme": "dark",
  "colour": "string",
  "accent": "string",
  "effective_colour": "string",
  "effective_accent": "string",
  "logo": {
    "url": "string",
    "width": 1,
    "height": 1,
    "filename": "string",
    "sha256": "string"
  },
  "checks": [
    {
      "name": "accent",
      "colour": "string",
      "ratio": 1.5,
      "minimum": 1.5,
      "passes": true
    }
  ],
  "updated_at": "2026-09-21T09:30:00Z",
  "updated_by": "string"
}

Download a company's logo

The stored PNG. Its address in GET /v1/entities/{entity}/brand changes with the file, so a browser keeps it for a day.

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

Responses

Status Meaning Body
200 The logo as a PNG. image/png
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 brand_no_logo: the company has no logo.
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

Upload a company's logo

Send multipart/form-data with the image in the field file. It is read by its bytes, reduced to at most 1200 x 480 pixels keeping its proportions and kept as a PNG without metadata; it replaces the company's logo on the app's top bar, on its PDFs, its e-mails to customers, the customer's page of a quote and its website forms. 422 brand_logo_empty, brand_logo_too_large, brand_logo_svg or brand_logo_invalid. Audited as brand.logo with the PNG's SHA-256; sending the same file again changes nothing that shows.

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

Parameters

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

Request body

multipart/form-data (required): Body_upload_logo_v1_entities__entity__brand_logo_post

Field Type Required Description
file string yes A PNG, JPEG, WebP or GIF image, at most 2 MB. SVG is refused.

Example request

curl -X POST "$ERP_URL/v1/entities/CH01/brand/logo" \
  -H "Authorization: Bearer $ERP_KEY" \
  -F "file=@statement.xml"

Responses

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

{
  "entity": "string",
  "theme": "dark",
  "colour": "string",
  "accent": "string",
  "effective_colour": "string",
  "effective_accent": "string",
  "logo": {
    "url": "string",
    "width": 1,
    "height": 1,
    "filename": "string",
    "sha256": "string"
  },
  "checks": [
    {
      "name": "accent",
      "colour": "string",
      "ratio": 1.5,
      "minimum": 1.5,
      "passes": true
    }
  ],
  "updated_at": "2026-09-21T09:30:00Z",
  "updated_by": "string"
}

Remove a company's logo

The company's documents and pages show its name alone again. Audited as brand.logo_remove; removing a logo that is not there changes nothing.

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

Parameters

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

Example request

curl -X DELETE "$ERP_URL/v1/entities/CH01/brand/logo" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

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

{
  "entity": "string",
  "theme": "dark",
  "colour": "string",
  "accent": "string",
  "effective_colour": "string",
  "effective_accent": "string",
  "logo": {
    "url": "string",
    "width": 1,
    "height": 1,
    "filename": "string",
    "sha256": "string"
  },
  "checks": [
    {
      "name": "accent",
      "colour": "string",
      "ratio": 1.5,
      "minimum": 1.5,
      "passes": true
    }
  ],
  "updated_at": "2026-09-21T09:30:00Z",
  "updated_by": "string"
}

GET /v1/entities/{entity}/fiscal-years

List Fiscal Years

The entity's fiscal years, oldest first, each with its calendar, its first and last day, its periods (regular periods, then adjustment periods) and its year-end close (close: status, result and what is left to appropriate). unappropriated=true keeps the years whose general meeting is overdue while part of the result is unappropriated.

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

Parameters

In Name Type Required Description
path entity string yes Entity code, e.g. CH01 (GET /v1/entities).
query unappropriated boolean Only the years whose result is still unappropriated when the general meeting is overdue (a Swiss entity, six months after the year end, Art. 699 para. 2 OR): the list the Role Center cue counts. (default false)
query as_of string (date) or null The day the overdue rule is judged on, ISO 8601; default: today where the entity is.

Example request

curl "$ERP_URL/v1/entities/CH01/fiscal-years" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK array of FiscalYearOut
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)

[
  {
    "fiscal_year": 1,
    "calendar": "string",
    "year_end": "string",
    "end_weekday": "string",
    "weeks": 1,
    "adjustment_periods": 1,
    "start_date": "2026-09-21",
    "end_date": "2026-09-21",
    "periods": [
      {
        "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "fiscal_year": 1,
        "number": 1,
        "kind": "string",
        "start_date": "2026-09-21",
        "end_date": "2026-09-21",
        "status": "string",
        "closed_at": null,
        "closed_by": null
      }
    ],
    "close": {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "kind": "catch_up",
      "status": "cancelled",
      "result": "string",
      "appropriated": "string",
      "remainder": "string",
      "appropriation_overdue": true
    }
  }
]

POST /v1/entities/{entity}/fiscal-years

Open a fiscal year

Open a fiscal year by creating its periods: monthly, 4-4-5 / 4-5-4 / 5-4-4, or 13 four-week periods, optionally with one or two adjustment periods on the last day.

A year directly follows the last year (it starts the day after it ends) or directly precedes the first. Without calendar the year uses the calendar of the latest earlier year, else twelve calendar months. Returns the new periods, all open. Refused with 409 when the year exists or overlaps another, or when a year would be missing in between (fiscal_year_gap, with missing: the year to open first), 422 when the calendar does not give a year of about 12 months.

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

Parameters

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

Request body

application/json (required): FiscalYearRequest

Field Type Required Description
fiscal_year integer yes The fiscal year to open, 2000 to 2100, e.g. 2027. It is the calendar year in which the year ends. (min 2000; max 2100)
calendar FiscalCalendar or null How to divide the year into periods. Default: the calendar of the previous year opened with one, else twelve calendar months.

Example request

curl -X POST "$ERP_URL/v1/entities/CH01/fiscal-years" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "calendar": {
    "adjustment_periods": 1,
    "calendar": "4-4-5"
  },
  "fiscal_year": 2027
}'

Responses

Status Meaning Body
201 Created array of PeriodOut
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",
    "fiscal_year": 1,
    "number": 1,
    "kind": "string",
    "start_date": "2026-09-21",
    "end_date": "2026-09-21",
    "status": "string",
    "closed_at": "2026-09-21T09:30:00Z",
    "closed_by": "string"
  }
]

GET /v1/entities/{entity}/periods

List Periods

The entity's posting periods ordered by fiscal year and number, with their status (open or closed). Use the id of a period in the close endpoints.

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

Parameters

In Name Type Required Description
path entity string yes Entity code, e.g. CH01 (GET /v1/entities).
query fiscal_year integer or null Only the periods of this fiscal year, e.g. 2026.
query on string (date) or null Only the periods containing this date (ISO 8601, e.g. 2026-09-15); a regular period comes before an adjustment period on the same day.

Example request

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

Responses

Status Meaning Body
200 OK array of PeriodOut
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",
    "fiscal_year": 1,
    "number": 1,
    "kind": "string",
    "start_date": "2026-09-21",
    "end_date": "2026-09-21",
    "status": "string",
    "closed_at": "2026-09-21T09:30:00Z",
    "closed_by": "string"
  }
]

POST /v1/entities/{entity}/role-accounts

Add Role Accounts

Add the accounts of required roles the entity lacks (e.g. the cash discount roles of entities created before they existed) from its chart template. Refused, naming the codes, when a template code is already in use; repeating it adds nothing. Answers 201 with the lists added and present (empty added when nothing was missing).

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

Parameters

In Name Type Required Description
path entity string yes Entity code, e.g. CH01 (GET /v1/entities).
query chart string or null Chart template id to take the accounts from (GET /v1/charts); default: the template the entity was created from.

Example request

curl -X POST "$ERP_URL/v1/entities/CH01/role-accounts" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)"

Responses

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

{
  "entity": "string",
  "chart": "string",
  "added": [
    "string"
  ],
  "present": [
    "string"
  ]
}

GET /v1/industries

List the industries a company can choose

The industries a company may say it is in (its industry, set in POST /v1/setup, POST /v1/entities or PATCH /v1/entities/{entity}), each with how far it is built (ready, partial, planned), what the product does for it and the feature modules that serve it. The industry puts its screens first in the app's menu and on its Home; it switches nothing off. Needs the read scope.

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

Example request

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

Responses

Status Meaning Body
200 OK array of IndustryOut
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

Example response (shape)

[
  {
    "key": "ecommerce",
    "name": "string",
    "status": "partial",
    "summary": "string",
    "modules": [
      {
        "name": "string",
        "title": "string"
      }
    ]
  }
]

GET /v1/setup

Tell whether the organization waits for its setup

needed while the organization has no company (and is not a test organization): the web UI then shows its first administrator the setup wizard. Needs the read scope.

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

Example request

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

Responses

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

{
  "needed": true,
  "can_complete": true
}

POST /v1/setup

Set up the organization: Production, then Test

Create the organization's first company from the setup wizard's answers, then its Test environment.

Production is the organization itself: the company (code: the country and 01, e.g. CA01) with the chart of accounts of the chosen standard (GET /v1/setup/options), the periods of the fiscal year that holds today (a year is named by the calendar year it ends in) and the tax return period chosen, in one commit. Test is then made as a test copy of Production (POST /v1/test-copies), named after the organization with (Test); when it cannot be made, Production stands, test_environment_problem says why, and an administrator makes it from Settings, Test copies.

Refused with 409 once the organization has a company (a second request makes nothing) and in a test organization; 422 for an answer the country does not allow. Needs the admin scope and a person: an agent key is refused (403). Recorded in the audit trail (org.setup, entity.create, org.test_copy).

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

Request body

application/json (required): SetupInput

Field Type Required Description
name string yes The company's legal name. (min length 1; max length 200)
country string yes Where it is registered (GET /v1/setup/options). (pattern ^[A-Z]{2}$)
subdivision string or null The state (US) or province (Canada), ISO 3166-2; required there, refused elsewhere. (pattern ^[A-Z]{2}-[A-Z0-9]{1,3}$)
standard string or null The accounting standard's id, one of the country's. Omitted: the country's first (GET /v1/setup/options lists them, the default first).
currency string or null The currency of the books, one the country allows. Cannot be changed later. Omitted: the country's currency. (pattern ^[A-Z]{3}$)
fiscal_year_start_month integer The month the fiscal year starts, 1 to 12. (min 1; max 12; default 1)
tax_period string or null The tax return period, one of the country's; default: its first.
tax_number string or null The tax registration number, when asked. (max length 40)
street string or null Street. (max length 70)
building_number string or null Number. (max length 16)
postal_code string or null Postal code. (max length 16)
town string or null Town. (max length 35)
industry "ecommerce" | "general" | "hospitality" | "manufacturing" | "retail" | "services" | "trade" The company's industry (GET /v1/industries): general, hospitality, services, trade, retail, ecommerce or manufacturing. It puts the screens of the industry first in the app's menu and on its Home; it switches nothing off, and every operation works the same in every industry. Default general; it can be changed later. (default "general")

Example request

curl -X POST "$ERP_URL/v1/setup" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "building_number": "100",
  "country": "CA",
  "currency": "CAD",
  "fiscal_year_start_month": 1,
  "name": "Maple Analytics Inc.",
  "postal_code": "M5X 1A9",
  "standard": "aspe",
  "street": "King Street West",
  "subdivision": "CA-ON",
  "tax_number": "123456789RT0001",
  "tax_period": "quarter",
  "town": "Toronto"
}'

Responses

Status Meaning Body
201 Created SetupDone
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",
  "standard": "string",
  "currency": "string",
  "chart": "string",
  "framework": "string",
  "fiscal_year": 1,
  "tax_settings": false,
  "test_environment": {
    "org_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "name": "string",
    "created_at": "2026-09-21T09:30:00Z",
    "created_by": {},
    "masked": true,
    "cloned_at": "2026-09-21T09:30:00Z",
    "refresh_schedule": "off",
    "refresh_problem": "refresh_failed",
    "refresh_problem_at": "2026-09-21T09:30:00Z",
    "remove_requested_at": "2026-09-21T09:30:00Z"
  },
  "test_environment_problem": "string"
}

POST /v1/setup/companies

Add a further company from the setup wizard's answers

Add a company to an organization that has one, made exactly as POST /v1/setup makes the first: the chart of accounts of the chosen standard, the periods of the fiscal year that holds today and the tax settings of the return period chosen (tax_settings), in one commit, under the code given. Unlike POST /v1/entities, the answers are checked against what the country allows (GET /v1/setup/options).

Refused with 409 when the code is taken, 422 for an answer the country does not allow, and 403 for an agent key or a key without the admin scope. No Test is made: the organization's existing test copies keep what they were copied from. Recorded in the audit trail (org.company_add, entity.create). A retry with the same Idempotency-Key returns the first answer.

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

Request body

application/json (required): CompanyInput

Field Type Required Description
name string yes The company's legal name. (min length 1; max length 200)
country string yes Where it is registered (GET /v1/setup/options). (pattern ^[A-Z]{2}$)
subdivision string or null The state (US) or province (Canada), ISO 3166-2; required there, refused elsewhere. (pattern ^[A-Z]{2}-[A-Z0-9]{1,3}$)
standard string or null The accounting standard's id, one of the country's. Omitted: the country's first (GET /v1/setup/options lists them, the default first).
currency string or null The currency of the books, one the country allows. Cannot be changed later. Omitted: the country's currency. (pattern ^[A-Z]{3}$)
fiscal_year_start_month integer The month the fiscal year starts, 1 to 12. (min 1; max 12; default 1)
tax_period string or null The tax return period, one of the country's; default: its first.
tax_number string or null The tax registration number, when asked. (max length 40)
street string or null Street. (max length 70)
building_number string or null Number. (max length 16)
postal_code string or null Postal code. (max length 16)
town string or null Town. (max length 35)
industry "ecommerce" | "general" | "hospitality" | "manufacturing" | "retail" | "services" | "trade" The company's industry (GET /v1/industries): general, hospitality, services, trade, retail, ecommerce or manufacturing. It puts the screens of the industry first in the app's menu and on its Home; it switches nothing off, and every operation works the same in every industry. Default general; it can be changed later. (default "general")
code string yes Short unique code, 2 to 20 characters of A-Z, 0-9, _ and -, e.g. CH02; it names the company in every URL. (pattern ^[A-Z0-9_-]{2,20}$)

Example request

curl -X POST "$ERP_URL/v1/setup/companies" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "code": "CH02",
  "country": "CH",
  "currency": "CHF",
  "fiscal_year_start_month": 1,
  "name": "Muster Services AG",
  "standard": "ch_co",
  "tax_number": "CHE-123.456.788 MWST",
  "tax_period": "quarter"
}'

Responses

Status Meaning Body
201 Created CompanyDone
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",
  "standard": "string",
  "currency": "string",
  "chart": "string",
  "framework": "string",
  "fiscal_year": 1,
  "tax_settings": false
}

GET /v1/setup/options

List what the setup wizard offers per country

The countries served (the EU, the United Kingdom, Switzerland and Liechtenstein, the United States and Canada), each with its currency, the currencies its books may be kept in, the accounting standards a company there may report under (the default first) and the chart each starts from, its indirect tax, the return periods allowed, what its tax registration number is called and the states or provinces to choose from. Needs the read scope.

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

Example request

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

Responses

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

Example response (shape)

{
  "countries": [
    {
      "country": "string",
      "name": "string",
      "region": "ca",
      "currency": "string",
      "currencies": [
        "string"
      ],
      "standards": [
        null
      ],
      "tax": "gst_hst",
      "tax_periods": [
        "string"
      ],
      "tax_number_label": "string",
      "vat_return_form": true,
      "subdivisions": [
        null
      ]
    }
  ]
}

Schemas

AccountChange

Field Type Required Description
account AccountOut yes The account as it is now. While a change waits for a second person it is unchanged.
status "applied" | "pending_approval" yes applied (the account has changed, or nothing needed to change) or pending_approval (a second person decides; approval_id).
changed array of string yes The fields that changed (name, role, report_line, active, vat_recovery_percent); with pending_approval, the ones that will change once approved.
approval_id string (uuid) or null The approval request of a change that waits for a second person; decide it with POST /v1/approvals/{approval_id}/approve or /reject.

AccountInput

Field Type Required Description
code string yes Account number, unique in the entity, e.g. 6510.
name string yes Account name, e.g. Telefon und Internet.
type "asset" | "equity" | "expense" | "liability" | "revenue" yes asset, liability, equity, revenue or expense; decides the normal balance side and which report it appears in.
report_line string yes Where the account appears in the statements, as a dotted key such as pl.opex.other, pl.revenue or bs.assets.current.cash. Use a line the chart already uses for the same type: each line holds one type of account (422 otherwise).
role string or null The purpose the services use the account for, e.g. bank, ar_control, vat_input, default_expense; null for an ordinary account.
control boolean True for a control account, which takes postings only from its subledger (receivables, payables, bank, fixed assets); default false. (default false)
currency string or null ISO 4217 code when the account only accepts one currency, e.g. EUR; null (default) accepts any.
vat_recovery_percent decimal string or null How much of the input VAT of a bill line booked to the account the company may deduct, in percent (0 to 100), when the line states none (ADR-0079): e.g. 0 on an account for gifts whose VAT the law excludes, 50 for a car used half privately. The rest of the VAT is booked as part of the cost on this account. Null: all of it. (min 0; max 100)

AccountOut

Field Type Required Description
id string (uuid) yes Id (uuid) of the account.
code string yes Account number, unique in the entity.
name string yes The account's name, the one the company keeps its books under; what official documents and filings print. Clients show it in their reader's language.
type string yes asset, liability, equity, revenue or expense.
report_line string yes The statement line the account is grouped under, e.g. pl.opex.other.
role string or null yes The purpose the services use the account for, e.g. bank; null for an ordinary account.
is_control boolean yes True for a control account, which only its subledger posts to.
currency string or null yes The only currency the account accepts (ISO 4217); null accepts any.
active boolean yes False for an account that no longer accepts postings.
vat_recovery_percent string or null How much of the input VAT of a bill line booked to the account the company may deduct, in percent (0 to 100), when the line states none (ADR-0079): e.g. 0 on an account for gifts whose VAT the law excludes, 50 for a car used half privately. The rest of the VAT is booked as part of the cost on this account. Null: all of it.

AccountUpdate

Changes to an account of the chart. Only the fields sent change; send role: null to take a role away. The number, type and currency of an account are fixed.

Field Type Required Description
role string or null The purpose the services use the account for, e.g. retained_earnings or deferred_tax_asset (GET /v1/entities/{entity}/accounts shows the roles in use). Send null to take the role away; omit to leave it. The role must be one the services know and fit the account's type (422), and no other account of the entity may hold it (409). A control role is refused (409) on an account that already has postings from outside its subledger. Changing a control or required role needs a second person: the answer is 202 with a pending approval. (max length 64; pattern ^[a-z][a-z0-9_]*$)
name string or null A new name for the account, e.g. Telefon und Internet; the number, type and postings stay as they are. Omit to leave it. (min length 1; max length 200)
report_line string or null The statement line the account is grouped under, e.g. pl.opex.other; each line holds one type of account, so an expense account goes on an expense line, never on a revenue or balance-sheet one (422). Omit to leave it. (max length 120; pattern `^(bs
active boolean or null False stops postings to the account, true allows them again. Refused (409, naming why) while the account holds a role, is a control account, carries a balance (a P&L account: a result in a year not closed to zero), is named by unfinished work (an entry, invoice, bill, order, payment or recurring invoice), or while an asset, product, subscription, contract, party or setting posts to it. Omit to leave it.
vat_recovery_percent decimal string or null How much of the input VAT of a bill line booked to the account the company may deduct, in percent (0 to 100), when the line states none (ADR-0079): e.g. 0 on an account for gifts whose VAT the law excludes, 50 for a car used half privately. The rest of the VAT is booked as part of the cost on this account. Null: all of it. Send null to take it away; omit to leave it. Bills already entered keep theirs. (min 0; max 100)
reason string or null Why; kept in the audit trail and shown to the second person who decides a change of a control or required role. (min length 3; max length 500)

Body_upload_logo_v1_entities__entity__brand_logo_post

Field Type Required Description
file string yes A PNG, JPEG, WebP or GIF image, at most 2 MB. SVG is refused.

BrandOut

A company's brand as the app, its documents and its pages show it.

Field Type Required Description
entity string yes The company's code.
theme "dark" | "light" | "system" yes How the app looks in this company: light, dark or system (the device's setting).
colour string or null yes The brand colour, #rrggbb; null: the product's own.
accent string or null yes The accent colour, #rrggbb; null: the brand colour.
effective_colour string yes The brand colour in use (the default when none).
effective_accent string yes The accent colour in use.
logo LogoOut or null yes The logo; null: none.
checks array of ContrastOut yes The contrast of the colours in use.
updated_at string (date-time) or null yes When it was last changed; null: never.
updated_by string or null yes Who changed it last.

BrandUpdate

Only the fields sent change; null sets a colour back to the default.

Field Type Required Description
theme "dark" | "light" | "system" or null light, dark or system.
colour string or null #rrggbb (or #rgb); at least 4.5:1 against white. null: the default. (max length 7)
accent string or null #rrggbb (or #rgb); at least 3:1 against white. null: the brand colour. (max length 7)

CompanyDone

Field Type Required Description
entity string yes The code of the company created.
standard string yes The accounting standard it reports under.
currency string yes The currency of its books.
chart string yes The chart template its accounts were copied from.
framework string yes Its accounting framework.
fiscal_year integer yes The fiscal year whose periods were opened.
tax_settings boolean True when its tax settings (method and return period) were saved; false where the country has none to set (US sales tax) or keeps the defaults (Liechtenstein). (default false)

CompanyInput

The setup wizard's answers for a further company of an organization that has one.

Field Type Required Description
name string yes The company's legal name. (min length 1; max length 200)
country string yes Where it is registered (GET /v1/setup/options). (pattern ^[A-Z]{2}$)
subdivision string or null The state (US) or province (Canada), ISO 3166-2; required there, refused elsewhere. (pattern ^[A-Z]{2}-[A-Z0-9]{1,3}$)
standard string or null The accounting standard's id, one of the country's. Omitted: the country's first (GET /v1/setup/options lists them, the default first).
currency string or null The currency of the books, one the country allows. Cannot be changed later. Omitted: the country's currency. (pattern ^[A-Z]{3}$)
fiscal_year_start_month integer The month the fiscal year starts, 1 to 12. (min 1; max 12; default 1)
tax_period string or null The tax return period, one of the country's; default: its first.
tax_number string or null The tax registration number, when asked. (max length 40)
street string or null Street. (max length 70)
building_number string or null Number. (max length 16)
postal_code string or null Postal code. (max length 16)
town string or null Town. (max length 35)
industry "ecommerce" | "general" | "hospitality" | "manufacturing" | "retail" | "services" | "trade" The company's industry (GET /v1/industries): general, hospitality, services, trade, retail, ecommerce or manufacturing. It puts the screens of the industry first in the app's menu and on its Home; it switches nothing off, and every operation works the same in every industry. Default general; it can be changed later. (default "general")
code string yes Short unique code, 2 to 20 characters of A-Z, 0-9, _ and -, e.g. CH02; it names the company in every URL. (pattern ^[A-Z0-9_-]{2,20}$)

ContrastOut

Field Type Required Description
name "accent" | "colour" yes Which colour is checked.
colour string yes The colour checked, #rrggbb (the default when none is set).
ratio number yes Its contrast ratio against white (WCAG 2.2), 1 to 21.
minimum number yes What it must reach: 4.5 for the brand colour (text on white, white on it), 3 for the accent (rules and bands).
passes boolean yes Whether it reaches the minimum.

CountryOption

Field Type Required Description
country string yes ISO 3166-1 alpha-2 code.
name string yes The country's name in English.
region "ca" | "ch" | "eu" | "no" | "uk" | "us" yes eu, no (Norway), uk, ch (Switzerland and Liechtenstein), us or ca.
currency string yes The country's currency, the default of the books.
currencies array of string yes The currencies the books may be kept in.
standards array of FrameworkOption yes The accounting standards a company there may report under, the default first.
tax "gst_hst" | "sales_tax" | "vat" yes The indirect tax: vat, sales_tax (US, per state) or gst_hst (Canada).
tax_periods array of string yes The return periods allowed, the default first (month, two_months, quarter, half_year, year); empty when none is asked.
tax_number_label string or null yes What the tax registration number is called; null when none is asked.
vat_return_form boolean yes Whether the VAT return is prepared on the official form; false: VAT is booked and reported per rate, and the return is filed outside the books for now.
subdivisions array of Subdivision yes The states or provinces, one of which must be chosen; empty when none is.

EntityDetailOut

One entity, with what waits for a second person about it.

Field Type Required Description
id string (uuid) yes Id (uuid) of the entity.
code string yes The entity code, e.g. CH01; the {entity} of other operations.
name string yes Legal name.
country string yes ISO 3166-1 alpha-2 country code.
subdivision string or null yes ISO 3166-2 code of the state or canton, e.g. DE-BY; null if none.
functional_currency string yes ISO 4217 code of the currency the books are kept in.
fiscal_year_start_month integer yes Month the fiscal year starts, 1 to 12.
framework string yes Accounting framework: ifrs, us_gaap or local.
vat_number string or null yes The entity's VAT number; null if not set.
street string or null Street of the address; null if not set.
building_number string or null Building number of the address; null if not set.
postal_code string or null Postal code of the address; null if not set.
town string or null Town of the address; null if not set.
contact_name string or null Seller contact name on e-invoices; null if not set.
contact_phone string or null Seller contact phone on e-invoices; null if not set.
contact_email string or null Seller contact email on e-invoices; null if not set.
electronic_address string or null Seller electronic address on e-invoices; null if not set.
electronic_address_scheme string or null Code of the electronic address scheme (EAS), e.g. EM; null if not set.
posting_approval_limit string or null The posting approval limit in the functional currency: whatever a person posts (a manual journal, a bill, an invoice, a payment, a refund, a VAT settlement, a revaluation, a depreciation run) whose functional amount is above it waits for a second person, and so does its reversal. A new company starts at about CHF 100,000 in its currency as a round figure (100000.00 CHF, EUR, USD, GBP or CAD, 1000000.00 SEK, 15000000 JPY). Null: no limit.
industry "ecommerce" | "general" | "hospitality" | "manufacturing" | "retail" | "services" | "trade" The company's industry (GET /v1/industries): general, hospitality, services, trade, retail, ecommerce or manufacturing. It puts the screens of the industry first in the app's menu and on its Home; it switches nothing off, and every operation works the same in every industry. (default "general")
posting_limit_request PostingLimitRequest or null The request to raise or remove posting_approval_limit that waits for a second person; null when none waits.
time_zone string yes The IANA time zone the entity's days are counted in, e.g. Europe/Zurich: today, the default date of its documents and the latest day a check accepts are the day it is there (its state's or province's in the United States and Canada).

EntityInput

Field Type Required Description
street string or null Street of the entity's address, at most 70 characters. (max length 70)
building_number string or null Building number of the address, at most 16 characters. (max length 16)
postal_code string or null Postal code of the address, at most 16 characters. (max length 16)
town string or null Town of the address, at most 35 characters. (max length 35)
contact_name string or null Seller contact (BT-41).
contact_phone string or null Seller contact phone (BT-42).
contact_email string or null Seller contact email (BT-43).
electronic_address string or null Seller electronic address (BT-34); defaults to contact_email.
electronic_address_scheme string or null EAS code, e.g. EM (email), 9930 (German VAT id), 0204.
code string yes Short unique code, 2 to 20 characters of A-Z, 0-9, _ and -, e.g. CH01; it names the entity in every URL. (pattern ^[A-Z0-9_-]{2,20}$)
name string yes Legal name, e.g. Demo AG.
country string yes ISO 3166-1 alpha-2 country code, e.g. CH or DE; decides the VAT rules. (pattern ^[A-Z]{2}$)
subdivision string or null ISO 3166-2 code of the state or canton, e.g. DE-BY; null when omitted. (pattern ^[A-Z]{2}-[A-Z0-9]{1,3}$)
functional_currency string or null ISO 4217 code of the currency the books are kept in, e.g. CHF. Cannot be changed later. Omitted: the currency of its country (422 entity_currency_needed where that is not known). (pattern ^[A-Z]{3}$)
fiscal_year_start_month integer Month the fiscal year starts, 1 to 12; default 1 (January). (min 1; max 12; default 1)
framework "ifrs" | "local" | "us_gaap" Accounting framework: ifrs (default), us_gaap or local. (default "ifrs")
vat_number string or null The entity's VAT number, e.g. CHE-123.456.788 MWST or DE123456788; null when omitted. For a Swiss or German entity its format is checked (422); it is printed on invoices and is required on them when the entity is VAT-registered.
chart string Chart template id (GET /v1/charts), e.g. ch_kmu; default ifrs_generic. GET /v1/charts?country= marks the country's standard chart, which the operator's provisioning uses. (default "ifrs_generic")
fiscal_years array of integer Years to open periods for.
fiscal_calendar FiscalCalendar or null Calendar for those years (default: twelve calendar months).
industry "ecommerce" | "general" | "hospitality" | "manufacturing" | "retail" | "services" | "trade" The company's industry (GET /v1/industries): general, hospitality, services, trade, retail, ecommerce or manufacturing. It puts the screens of the industry first in the app's menu and on its Home; it switches nothing off, and every operation works the same in every industry. Default general. (default "general")

EntityOut

Field Type Required Description
id string (uuid) yes Id (uuid) of the entity.
code string yes The entity code, e.g. CH01; the {entity} of other operations.
name string yes Legal name.
country string yes ISO 3166-1 alpha-2 country code.
subdivision string or null yes ISO 3166-2 code of the state or canton, e.g. DE-BY; null if none.
functional_currency string yes ISO 4217 code of the currency the books are kept in.
fiscal_year_start_month integer yes Month the fiscal year starts, 1 to 12.
framework string yes Accounting framework: ifrs, us_gaap or local.
vat_number string or null yes The entity's VAT number; null if not set.
street string or null Street of the address; null if not set.
building_number string or null Building number of the address; null if not set.
postal_code string or null Postal code of the address; null if not set.
town string or null Town of the address; null if not set.
contact_name string or null Seller contact name on e-invoices; null if not set.
contact_phone string or null Seller contact phone on e-invoices; null if not set.
contact_email string or null Seller contact email on e-invoices; null if not set.
electronic_address string or null Seller electronic address on e-invoices; null if not set.
electronic_address_scheme string or null Code of the electronic address scheme (EAS), e.g. EM; null if not set.
posting_approval_limit string or null The posting approval limit in the functional currency: whatever a person posts (a manual journal, a bill, an invoice, a payment, a refund, a VAT settlement, a revaluation, a depreciation run) whose functional amount is above it waits for a second person, and so does its reversal. A new company starts at about CHF 100,000 in its currency as a round figure (100000.00 CHF, EUR, USD, GBP or CAD, 1000000.00 SEK, 15000000 JPY). Null: no limit.
industry "ecommerce" | "general" | "hospitality" | "manufacturing" | "retail" | "services" | "trade" The company's industry (GET /v1/industries): general, hospitality, services, trade, retail, ecommerce or manufacturing. It puts the screens of the industry first in the app's menu and on its Home; it switches nothing off, and every operation works the same in every industry. (default "general")
time_zone string yes The IANA time zone the entity's days are counted in, e.g. Europe/Zurich: today, the default date of its documents and the latest day a check accepts are the day it is there (its state's or province's in the United States and Canada).

EntityUpdate

Fields that can change after an entity was created (null leaves a field as is, but the posting approval limit, which null removes).

Field Type Required Description
street string or null Street of the address, at most 70 characters; omit or null to keep it. (max length 70)
building_number string or null Building number, at most 16 characters; omit or null to keep it. (max length 16)
postal_code string or null Postal code, at most 16 characters; omit or null to keep it. (max length 16)
town string or null Town, at most 35 characters; omit or null to keep it. (max length 35)
contact_name string or null Seller contact (BT-41).
contact_phone string or null Seller contact phone (BT-42).
contact_email string or null Seller contact email (BT-43).
electronic_address string or null Seller electronic address (BT-34); defaults to contact_email.
electronic_address_scheme string or null EAS code, e.g. EM (email), 9930 (German VAT id), 0204.
name string or null New legal name; omit or null to keep it.
vat_number string or null New VAT number (format checked for a Swiss or German entity, 422); omit or null to keep it.
industry "ecommerce" | "general" | "hospitality" | "manufacturing" | "retail" | "services" | "trade" or null The company's industry (GET /v1/industries): general, hospitality, services, trade, retail, ecommerce or manufacturing. It puts the screens of the industry first in the app's menu and on its Home; it switches nothing off, and every operation works the same in every industry. Omit or null to keep it; audited with the other changes.
posting_approval_limit decimal string or null The posting approval limit in the functional currency: whatever a person posts (a manual journal, a bill, an invoice, a payment, a refund, a VAT settlement, a revaluation, a depreciation run) whose functional amount is above it waits for a second person, and so does its reversal. A new company starts at about CHF 100,000 in its currency as a round figure (100000.00 CHF, EUR, USD, GBP or CAD, 1000000.00 SEK, 15000000 JPY). Omit it to keep the limit; null removes it (a one-person company). Only a person with the admin scope changes it (403 posting_limit_admin_only). A lower limit applies at once; raising or removing it waits for a second person (policy action change_posting_limit): the answer keeps the old limit and names the request in posting_limit_request (409 posting_limit_change_waiting while one waits, until it is decided or its requester withdraws it with POST /v1/approvals/{approval_id}/withdraw). A person alone in the organization (one active person, nobody else disabled or demoted in the last 30 days) changes it at once. Audited as entity.posting_limit with the value before and after (and alone when it applied so). (greater than 0)

FiscalYearOut

Field Type Required Description
fiscal_year integer yes The fiscal year, the calendar year in which it ends.
calendar string yes monthly, 4-4-5, 4-5-4, 5-4-4 or 13x4.
year_end string yes month_end, last_weekday or nearest_weekday.
end_weekday string or null yes The weekday a week-based year ends on; null on a monthly calendar.
weeks integer or null yes Number of weeks (52 or 53) of a week-based year; null on a monthly calendar.
adjustment_periods integer yes Number of one-day adjustment periods on the last day (0 to 2).
start_date string (date) yes First day of the year (ISO 8601).
end_date string (date) yes Last day of the year (ISO 8601).
periods array of PeriodOut yes The periods of the year: regular ones, then adjustment periods.
close YearCloseSummary or null The year-end close of the year (the one holding it, else the newest): status, result, what is appropriated and what is left, and whether the general meeting is overdue; null when the year was never proposed for closing.

FiscalYearRequest

Field Type Required Description
fiscal_year integer yes The fiscal year to open, 2000 to 2100, e.g. 2027. It is the calendar year in which the year ends. (min 2000; max 2100)
calendar FiscalCalendar or null How to divide the year into periods. Default: the calendar of the previous year opened with one, else twelve calendar months.

FrameworkOption

Field Type Required Description
id string yes The standard's id, the standard of POST /v1/setup.
label string yes Its name, e.g. US GAAP.
framework "ifrs" | "local" | "us_gaap" yes The entity's accounting framework it is recorded as.
chart string yes The chart template the company starts from.

IndustryModuleOut

Field Type Required Description
name string yes The feature module's name, e.g. hospitality.
title string yes Its title, e.g. Hospitality.

IndustryOut

Field Type Required Description
key "ecommerce" | "general" | "hospitality" | "manufacturing" | "retail" | "services" | "trade" yes The industry's key, the industry of a company.
name string yes Its name in English; the app shows its own translation.
status "partial" | "planned" | "ready" yes How far it is built: ready (its own screens exist), partial (the general screens serve it, some of its own are missing) or planned (nothing of its own yet: the general layout).
summary string yes What the product does for it, and what it does not yet.
modules array of IndustryModuleOut yes The feature modules that serve it, whose screens come first in it.

LogoOut

Field Type Required Description
url string yes Where the PNG is (GET, the read scope); changes with the file.
width integer yes Its width in pixels.
height integer yes Its height in pixels.
filename string or null yes The name of the file it was uploaded as.
sha256 string yes SHA-256 of the stored PNG.

PostingLimitRequest

A request to raise or remove the posting approval limit that waits for a second person.

Field Type Required Description
approval_id string (uuid) yes Id (uuid) of the approval request; a second person approves it (POST /v1/approvals/{approval_id}/approve), or the person who asked withdraws it (POST /v1/approvals/{approval_id}/withdraw).
current string or null yes The limit now, which holds until then; null: none.
proposed string or null yes The limit once approved; null: no limit.
requested_by object yes Who asked (type, id, name).
requested_at string (date-time) yes When it was asked (UTC).

RoleAccounts

Field Type Required Description
entity string yes Code of the entity.
chart string yes The chart template the accounts were taken from.
added array of string yes The accounts added: code and role.
present array of string yes Required roles the entity already had.

SetupDone

Field Type Required Description
entity string yes The code of the company created in Production.
standard string yes The accounting standard it reports under.
currency string yes The currency of its books.
chart string yes The chart template its accounts were copied from.
framework string yes Its accounting framework.
fiscal_year integer yes The fiscal year whose periods were opened.
tax_settings boolean True when its tax settings (method and return period) were saved; false where the country has none to set (US sales tax) or keeps the defaults (Liechtenstein). (default false)
test_environment CopyOut or null Test, the test copy made of Production; null if it failed.
test_environment_problem string or null Why Test could not be made (Production stands); make it from Settings, Test copies.

SetupInput

Field Type Required Description
name string yes The company's legal name. (min length 1; max length 200)
country string yes Where it is registered (GET /v1/setup/options). (pattern ^[A-Z]{2}$)
subdivision string or null The state (US) or province (Canada), ISO 3166-2; required there, refused elsewhere. (pattern ^[A-Z]{2}-[A-Z0-9]{1,3}$)
standard string or null The accounting standard's id, one of the country's. Omitted: the country's first (GET /v1/setup/options lists them, the default first).
currency string or null The currency of the books, one the country allows. Cannot be changed later. Omitted: the country's currency. (pattern ^[A-Z]{3}$)
fiscal_year_start_month integer The month the fiscal year starts, 1 to 12. (min 1; max 12; default 1)
tax_period string or null The tax return period, one of the country's; default: its first.
tax_number string or null The tax registration number, when asked. (max length 40)
street string or null Street. (max length 70)
building_number string or null Number. (max length 16)
postal_code string or null Postal code. (max length 16)
town string or null Town. (max length 35)
industry "ecommerce" | "general" | "hospitality" | "manufacturing" | "retail" | "services" | "trade" The company's industry (GET /v1/industries): general, hospitality, services, trade, retail, ecommerce or manufacturing. It puts the screens of the industry first in the app's menu and on its Home; it switches nothing off, and every operation works the same in every industry. Default general; it can be changed later. (default "general")

SetupOptions

Field Type Required Description
countries array of CountryOption yes The countries served, by name.

SetupStatus

Field Type Required Description
needed boolean yes True while the organization has no company and is not a test organization: its first administrator is asked to set it up.
can_complete boolean yes True when the caller may set it up (an administrator, a person).

Subdivision

Field Type Required Description
code string yes ISO 3166-2 code, e.g. US-NY.
name string yes Its name, e.g. New York.

YearCloseSummary

The close of a fiscal year as the list of fiscal years shows it.

Field Type Required Description
id string (uuid) yes Id of the year close.
kind "catch_up" | "year_end" yes year_end or catch_up.
status "cancelled" | "closed" | "pending" | "reopened" yes pending, closed, reopened or cancelled.
result string yes The result of the year, profit positive.
appropriated string yes What is appropriated so far, signed like the result.
remainder string yes What is left to appropriate.
appropriation_overdue boolean yes True when the general meeting is overdue and a remainder is unappropriated.
Stabiso, the Enterprise System of Record · generated from the code and its guides · release 6f03a5e846b3