StabisoDocs

API reference

Test copies

A test organization with the organization's setup (companies, chart of accounts, customers, vendors, products, people) and empty books, to try things out without touching the real ones; removing one; and sample data for a test organization.

Operation Summary Scope Idempotency-Key
POST /v1/entities/{entity}/sample-data Add sample data to a test organization admin required
GET /v1/test-copies List the test copies of the organization admin
POST /v1/test-copies Make a test copy of the organization admin required
DELETE /v1/test-copies/{copy_id} Remove a test copy admin
POST /v1/test-copies/{copy_id}/refresh Refresh a test copy from the organization admin required
PUT /v1/test-copies/{copy_id}/schedule Set when a test copy is refreshed by itself admin

POST /v1/entities/{entity}/sample-data

Add sample data to a test organization

Book a month of sample business into an entity of a test organization (a test copy or a demo), to have something to look at and try things on: three sample customers and two sample vendors (created once, codes SAMPLE-...), four sales invoices and two bills dated in the current month up to today, the first customer's payment of the first invoice and the payment of the first bill. Everything goes through the ordinary services, with the entity's own VAT and accounts, booked as the system actor sample. Asking again adds another set.

Refused with 409 in an organization that is not a test organization (sample data never goes into real books) or when today's period is closed; 403 for an agent. Needs the admin scope and an Idempotency-Key. Recorded in the audit trail (sample_data.add).

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

Parameters

In Name Type Required Description
path entity string yes Code (or id) of the entity, e.g. CH01.

Example request

curl -X POST "$ERP_URL/v1/entities/{entity}/sample-data" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)"

Responses

Status Meaning Body
201 Created SampleDataOut
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",
  "customers": 1,
  "vendors": 1,
  "invoices": 1,
  "bills": 1,
  "payments": 1
}

GET /v1/test-copies

List the test copies of the organization

The test organizations made from this one, oldest first. Needs the admin scope.

Required scope admin (admin implies every scope)
Operation id list_test_copies_v1_test_copies_get

Example request

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

Responses

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

[
  {
    "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"
  }
]

POST /v1/test-copies

Make a test copy of the organization

Make a new test organization that is a clone of this one, to try things out or work on without touching the real books: everything of the organization comes across exactly as it is, under new ids: its companies (entities), fiscal years and periods, the chart of accounts, settings, customers, vendors, products, contracts and subscriptions, every journal entry, invoice, bill, payment, asset, bank statement, VAT return, stored document, plan and close, the audit trail, and its people with their roles (as invited: they sign in to the copy with their usual sign-in). The copy's books are proven to be the organization's own before the answer is given: every hash chain verifies and every account of every company has the same balance in every currency (409 otherwise, and nothing is made). API keys, sessions, the security log and exports stay behind.

With masked, who the business partners are does not come across: the names, e-mails, e-invoicing addresses, streets and numbers, IBANs and contacts of customers, vendors and prospects, the counterparties of bank lines and the addresses documents were sent to become mock values (Customer 001, contact-001@example.com), the same real value always the same mock, wherever they appear in free text (descriptions, notes, payment files, the audit trail); notes about them, remittances and the descriptions of journal entries typed by hand or booked from a bank line (a salary naming its employee) become (masked), wherever they were copied, and stored files a placeholder; the audit trail and approvals keep only what happened (amounts, codes, dates, statuses), not about whom, and a change of a partner's details still waiting arrives rejected. Nothing else changes: codes, references, currencies and actions keep their values. The organization's own setup (companies, bank accounts, chart of accounts, products, settings, including a partner's name it holds, such as an account named after a customer), its intercompany partners, partners' codes, amounts, dates, tax data and the people who sign in stay exactly as they are, so the books are still proven to be the organization's own. For testing with people who should not see the real customers and vendors.

Each person of the organization finds the test organization in the list of organizations when signing in, labelled as a test. Nothing leaves a test copy: no e-mail to a customer, no payment file and no e-invoice (its customers, vendors and banks are the real ones); remove it with DELETE /v1/test-copies/{copy_id} when it is no longer needed. A test organization cannot itself be copied (409), and an organization has at most 5 test copies at a time (409). Needs the admin scope and a person: an agent key is refused (403). Recorded in the audit trail of both organizations (org.test_copy).

A retry with the same Idempotency-Key returns the first answer and makes nothing more.

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

Request body

application/json (required): CopyRequest

Field Type Required Description
name string or null The name of the test organization, up to 200 characters. Default: the organization's name followed by (test). (max length 200)
masked boolean Mask the business partners: the names, e-mails, streets, IBANs and contacts of customers, vendors and prospects become mock values everywhere in the copy, and its stored files placeholders. Amounts, setup and the books stay the same. (default false)

Example request

curl -X POST "$ERP_URL/v1/test-copies" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "masked": true,
  "name": "Muster AG (UAT)"
}'

Responses

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

{
  "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"
}

DELETE /v1/test-copies/{copy_id}

Remove a test copy

Remove a test organization made from this one, with everything in it: its books, its setup and its people's access to it. The answer is 202 with remove_requested_at set: from then on nobody can sign in to the copy or change anything in it. It is deleted for good between one and two hours later (one copy after the other, the one asked for first), and then leaves GET /v1/test-copies; it no longer counts towards the 5 copies. Only test copies of this organization can be removed (404 for any other id); a real organization never can. Asking again changes nothing. Needs the admin scope and a person: an agent key is refused (403). Recorded in the audit trail (org.test_copy_remove) and, when it is deleted, in the platform's audit.

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

Parameters

In Name Type Required Description
path copy_id string (uuid) yes Id (uuid) of the test copy.

Example request

curl -X DELETE "$ERP_URL/v1/test-copies/{copy_id}" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
202 Successful Response CopyOut
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)

{
  "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"
}

POST /v1/test-copies/{copy_id}/refresh

Refresh a test copy from the organization

Clone this organization again into one of its test copies, as it is now: everything in the copy is replaced, and whatever was done in it is lost (entries, documents, settings, its audit trail; only its log of security events stays). The copy keeps its id and name, so its people find it where it was; they are signed out of it. Its books are proven to be this organization's own, as when a copy is made (409 otherwise, and the copy stays as it was). A masked copy is masked again. cloned_at tells when it happened.

404 for anything that is not a test copy of this organization, 409 for a copy whose removal was asked for. Needs the admin scope and a person: an agent key is refused (403). Recorded in the audit trail of both organizations (org.test_copy_refresh). A retry with the same Idempotency-Key returns the first answer and refreshes nothing more.

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

Parameters

In Name Type Required Description
path copy_id string (uuid) yes Id (uuid) of the test copy.

Example request

curl -X POST "$ERP_URL/v1/test-copies/{copy_id}/refresh" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)"

Responses

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

{
  "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"
}

PUT /v1/test-copies/{copy_id}/schedule

Set when a test copy is refreshed by itself

Have the copy refreshed by itself, as POST /v1/test-copies/{copy_id}/refresh does: nightly refreshes it every night, weekly once a week (a week after it was last filled), off stops it. Every refresh replaces everything in the copy, so whatever was done in it since is lost; a copy that cannot be refreshed stays as it was until the next night. The refreshes are recorded in the audit trail of both organizations (org.test_copy_refresh), with who set the schedule. 404 and 409 as for a refresh. Needs the admin scope and a person: an agent key is refused (403). Recorded in the audit trail (org.test_copy_schedule); setting the schedule it has changes nothing.

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

Parameters

In Name Type Required Description
path copy_id string (uuid) yes Id (uuid) of the test copy.

Request body

application/json (required): ScheduleRequest

Field Type Required Description
refresh_schedule "nightly" | "off" | "weekly" yes nightly: the copy is refreshed every night; weekly: once a week; off: only when someone refreshes it.

Example request

curl -X PUT "$ERP_URL/v1/test-copies/{copy_id}/schedule" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "refresh_schedule": "nightly"
}'

Responses

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

{
  "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"
}

Schemas

CopyRequest

Field Type Required Description
name string or null The name of the test organization, up to 200 characters. Default: the organization's name followed by (test). (max length 200)
masked boolean Mask the business partners: the names, e-mails, streets, IBANs and contacts of customers, vendors and prospects become mock values everywhere in the copy, and its stored files placeholders. Amounts, setup and the books stay the same. (default false)

SampleDataOut

What POST /v1/entities/{entity}/sample-data booked.

Field Type Required Description
entity string yes The entity's code.
customers integer yes Sample customers created (0 when they existed already).
vendors integer yes Sample vendors created (0 when they existed already).
invoices integer yes Sales invoices posted.
bills integer yes Vendor bills posted.
payments integer yes Payments booked: the first invoice's and the first bill's.

ScheduleRequest

Field Type Required Description
refresh_schedule "nightly" | "off" | "weekly" yes nightly: the copy is refreshed every night; weekly: once a week; off: only when someone refreshes it.
Stabiso, the Enterprise System of Record · generated from the code and its guides · release 6f03a5e846b3