StabisoDocs

API reference

Payments

Receipts and payments with allocations, payment proposals and payment runs.

Operation Summary Scope Idempotency-Key
POST /v1/applications Apply an amount on account or a credit note to open documents draft required
GET /v1/entities/{entity}/open-credits List amounts on account and open credit notes read
POST /v1/entities/{entity}/payment-proposals Suggest vendor payments read
POST /v1/entities/{entity}/payment-runs Create the payments of a proposal draft required
POST /v1/payments Record a payment or receipt draft required
GET /v1/payments/{payment_id} Get a payment read
POST /v1/payments/{payment_id}/refund Pay back an amount on account draft required
POST /v1/payments/{payment_id}/reverse Reverse a payment or receipt draft required

POST /v1/applications

Apply an amount on account or a credit note to open documents

Apply what is left on account of a posted payment or receipt (payment), or the open amount of a posted credit note (credit_note), to open posted invoices or bills of the same customer or vendor, on application_date; a document in another currency is settled by the document_amount its allocation names in that currency (ADR-0054). One allocation per document and one entry that moves the amount on the control account from the payment or credit note to the documents; each side is relieved at the rate it is carried at (the payment's, the credit note's, the document's historical rate) and the difference is booked as realised FX. The entry goes through the approval policy (submit.policy); until it is posted the amounts are reserved on both sides. Refuses with 422 when the amounts are more than is left to apply or open on a document, a document cannot be settled by it (other party, kind or status), or the date is before the payment, the credit note or a document; with 404 for an unknown payment, credit note or document; with 409 when the period is closed, or a bill is blocked for payment (bill_payment_blocked: its purchase order variance waits for a second person's approval, as for a payment). All or nothing.

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

Request body

application/json (required): ApplicationInput

Field Type Required Description
entity string yes Code (or id) of the entity, e.g. CH01.
payment string or null Id or number of a posted payment or receipt with an amount on account to apply. Give this or credit_note.
credit_note string or null Id or number of a posted credit note with an open amount to apply. Give this or payment.
application_date string (date) yes The day the application takes effect (ISO 8601): on or after the payment or credit note and every document it settles, in an open period. The aging and the statement count it from this day.
allocations array of ApplyTo yes The invoices or bills it settles, each an open posted document of the same customer or vendor, with the amount applied (and, for a document in another currency, what it settles there). Together at most what is left on account (or open on the credit note). (min items 1)

Example request

curl -X POST "$ERP_URL/v1/applications" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "allocations": [
    {
      "amount": "250.00",
      "document": "INV-2026-000012"
    }
  ],
  "application_date": "2026-10-10",
  "entity": "CH01",
  "payment": "RCPT-2026-000004"
}'

Responses

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

{
  "source": "credit_note",
  "source_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "allocations": [
    "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  ],
  "status": "string",
  "fx_difference": "string",
  "left": "string",
  "submit": {
    "entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "status": "string",
    "number": "string",
    "policy": {
      "decision": "allow",
      "reason": "string",
      "rule_id": "string",
      "table_id": "string"
    },
    "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "reason": "string"
  }
}

GET /v1/entities/{entity}/open-credits

List amounts on account and open credit notes

What can still be applied to open invoices or bills with POST /v1/applications: posted payments and receipts with an amount on account left, and posted credit notes with an open amount, oldest first, with what is left of each (applications waiting for approval reserve theirs). 404 for an unknown customer or vendor.

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

Parameters

In Name Type Required Description
path entity string yes Entity code, e.g. CH01 (GET /v1/entities).
query party string or null Code (or id) of one customer or vendor; default: all of them.
query kind "customer" | "vendor" or null customer or vendor; default: both.

Example request

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

Responses

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

[
  {
    "source": "credit_note",
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "number": "string",
    "kind": "string",
    "party_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "party_code": "string",
    "party": "string",
    "date": "2026-09-21",
    "currency": "string",
    "amount": "string",
    "open": "string"
  }
]

POST /v1/entities/{entity}/payment-proposals

Suggest vendor payments

Suggest vendor payments: open bills due by due_until, or whose cash discount would expire by then, with the amount after the discount. Nothing is stored; confirm the reviewed lines with POST /v1/entities/{entity}/payment-runs. Each line says why it is proposed (overdue, due or cash_discount) and carries warnings such as a missing IBAN or a draft vendor. bank_balances gives, per currency, the bank account the run would pay from and its book balance on the payment date. 422 when cash discounts are taken but the entity has no cash discount account.

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

Parameters

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

Request body

application/json (required): ProposalCriteria

Field Type Required Description
payment_date string (date) yes The day the payments would be booked; cash discounts are offered while it is within their period. A preview may look ahead; the run itself is dated today at the latest, and the bank pays on the execution date chosen when the payment file is sent.
due_until string (date) or null Last payment date: bills due on or before it are proposed (default the payment date).
take_discounts boolean Deduct cash discounts still available on the payment date, and also propose bills not yet due whose discount would expire by due_until. (default true)
vendors array of string or null Vendor codes (default all).
currency string or null ISO 4217 code: propose only bills in this currency; default: all. (pattern ^[A-Z]{3}$)
bank_account string or null GL bank account code the run will pay from, as the run's bank_account; default: per currency. Only bank_balances depends on it.

Example request

curl -X POST "$ERP_URL/v1/entities/CH01/payment-proposals" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "due_until": "2026-10-15",
  "payment_date": "2026-09-30",
  "take_discounts": true,
  "vendors": [
    "V-BM",
    "V-IT"
  ]
}'

Responses

Status Meaning Body
200 OK PaymentProposal
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",
  "payment_date": "2026-09-21",
  "due_until": "2026-09-21",
  "take_discounts": true,
  "lines": [
    {
      "document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "number": "string",
      "external_number": "string",
      "vendor": "string",
      "vendor_name": "string",
      "currency": "string",
      "document_date": "2026-09-21",
      "due_date": "2026-09-21",
      "cash_discount_percent": "string",
      "cash_discount_date": "2026-09-21",
      "total": "string",
      "open": "string",
      "discount": "string",
      "amount": "string",
      "reason": "cash_discount",
      "payment_iban": "string",
      "payment_reference": "string",
      "warnings": [
        "string"
      ],
      "problems": [
        null
      ],
      "credit_available": "0.00",
      "preselected": true
    }
  ],
  "totals_by_currency": {},
  "skipped": [
    {
      "document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "number": "string",
      "vendor": "string",
      "vendor_name": "string",
      "currency": "string",
      "open": "string",
      "code": "string",
      "reason": "string"
    }
  ],
  "bank_balances": [
    {
      "currency": "string",
      "account": "string",
      "account_currency": "string",
      "balance": "string"
    }
  ]
}

POST /v1/entities/{entity}/payment-runs

Create the payments of a proposal

Create the payments of a reviewed proposal, all or none: one per vendor (a bill with a structured reference on its own), each through the approval policy: a payment is posted or pending_approval, counted in the result. Refuses with 422 when a line is not a bill of the entity, a bill is listed twice, or an amount or cash discount is not allowed, in which case no payment is created. A run that takes a bank account below zero in the books on the payment date is made, with one warnings line per account and its warning_reasons by code. Approved payments are released with POST /v1/payment-exports.

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

Parameters

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

Request body

application/json (required): PaymentRunInput

Field Type Required Description
payment_date string (date) yes Day the payments are booked (ISO 8601, e.g. 2026-09-30), today at the latest. The bank pays on the execution date of the payment file, which may be later but not after the cash discount period of a bill whose discount the payment takes.
bank_account string or null GL bank account code; default: per currency, as a payment's default bank account, refused when only a main account in another currency is left.
lines array of RunLine yes The reviewed proposal lines to pay, 1 to 1000 vendor bills with the amount and cash discount of each. (min items 1; max items 1000)

Example request

curl -X POST "$ERP_URL/v1/entities/CH01/payment-runs" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "bank_account": "1020",
  "lines": [
    {
      "amount": "1176.00",
      "discount": "24.00",
      "document": "BILL-2026-000001"
    }
  ],
  "payment_date": "2026-09-30"
}'

Responses

Status Meaning Body
201 Created PaymentRunResult
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",
  "payment_date": "2026-09-21",
  "payments": [
    {
      "payment_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "vendor": "string",
      "vendor_name": "string",
      "currency": "string",
      "amount": "string",
      "discount": "string",
      "documents": [
        "string"
      ],
      "status": "string",
      "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    }
  ],
  "posted": 1,
  "pending_approval": 1,
  "warnings": [
    "string"
  ],
  "warning_reasons": [
    {
      "words": "string",
      "code": "string",
      "details": {},
      "text": "string"
    }
  ]
}

POST /v1/payments

Record a payment or receipt

Record a payment (to a vendor) or a receipt (from a customer) and allocate it to open documents; realised FX is posted. An outgoing payment awaits the bank's execution on the payments-in-transit account until its bank statement line is matched, unless it is recorded as already executed by the bank (ADR-0060); a receipt goes to the bank. The allocations and on_account must add up to amount; each allocation settles one posted document of the party in the payment's currency. on_account keeps the rest on the party's account (an overpayment, an advance, or a payment of nothing yet): an open item of the party in the aging, the statement and its balances, booked at the payment's rate, applied later with POST /v1/applications. The payment's entry goes through the approval policy: the result's submit.policy is allow (posted and numbered) or require_approval (status pending_approval); deny answers 403. Refuses with 422 when the amounts do not add up, a document cannot be settled by this payment (wrong party, kind, status or currency), an allocation exceeds the open amount, a cash discount is not allowed or a receipt is dated after today (receipt_in_future, an outgoing one payment_in_future) or before a document it settles (payment_before_document), and with 404 for an unknown document, party or account. All or nothing: a refused payment leaves nothing behind. A payment that takes its bank account below zero in the books on its date is recorded, with a warnings line and its warning_reasons by code (the money may be there and not booked yet).

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

Request body

application/json (required): PaymentInput

Field Type Required Description
entity string yes Code (or id) of the entity paying or receiving, e.g. CH01.
direction "incoming" | "outgoing" yes incoming: a receipt from a customer; outgoing: a payment to a vendor.
party string yes Customer or vendor code (or id), e.g. C-DE or V-BM.
payment_date string (date) or null Value date of the payment (ISO 8601); default today where the company is. The exchange rate of this day gives the realised FX difference. The fiscal period must be open. A receipt (incoming) is not dated after today (receipt_in_future), nor is a payment made (payment_in_future: a payment file asks the bank for a later execution date); neither is dated before a document it settles (payment_before_document).
amount decimal string yes Total amount paid, a decimal string such as 1500.00; it must equal the sum of the allocation amounts and on_account (cash discounts are on top of it). (greater than 0)
currency string or null ISO 4217 code of the payment; default: the party's currency. A document in another currency is settled too: its allocation names what it settles in the document's currency (document_amount). (pattern ^[A-Z]{3}$)
bank_account string or null GL bank account code; default: the main bank account (role 'bank') when it holds the payment's currency, else the first active bank account in that currency, else the main one. A receipt collected by a payment provider (Shopify Payments) names the provider's balance (role 'provider_balance'), never a default.
reference string or null Free text reference, e.g. the bill number or a bank reference.
allocations array of AllocationInput-Input The documents the payment settles: each allocation names a posted document of the party and the amount applied. May be empty when the whole amount is on_account.
on_account decimal string The part of the amount allocated to no document, e.g. an overpayment or an advance: it stays on the party's account (an open item of the party in the aging and the statement) until it is applied to an invoice or bill with POST /v1/applications. Default 0: the allocations take the whole amount. (min 0; default "0")
bank_line_id string (uuid) or null Id of the bank statement line the payment records, when it is entered from a bank statement; such a payment counts as already executed and is not put into a payment file.
party_kind "customer" | "vendor" or null Defaults to customer for incoming, vendor for outgoing; set it for refunds.
executed boolean Outgoing payments only: true when the bank already executed the payment (paid in e-banking, by card or in cash): it is booked on the bank account at once and goes into no payment file. Default false: the payment awaits execution by the bank (a payment file, or a transfer still to be made) and is booked on the payments-in-transit account (role payments_in_transit) until the bank statement line that shows it is matched, which moves it to the bank account (ADR-0060). A payment recorded from a bank line (bank_line_id) and a receipt always go to the bank account. (default false)

Example request

curl -X POST "$ERP_URL/v1/payments" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "allocations": [
    {
      "amount": "1200.00",
      "document": "BILL-2026-000001"
    }
  ],
  "amount": "1200.00",
  "bank_account": "1020",
  "direction": "outgoing",
  "entity": "CH01",
  "party": "V-BM",
  "payment_date": "2026-09-30",
  "reference": "BM-4411"
}'

Responses

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

{
  "payment_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "status": "string",
  "fx_difference": "string",
  "discount": "0.00",
  "in_transit": false,
  "submit": {
    "entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "status": "string",
    "number": "string",
    "policy": {
      "decision": "allow",
      "reason": "string",
      "rule_id": "string",
      "table_id": "string"
    },
    "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "reason": "string"
  },
  "warnings": [
    "string"
  ],
  "warning_reasons": [
    {
      "words": "string",
      "code": "string",
      "details": {},
      "text": "string"
    }
  ]
}

GET /v1/payments/{payment_id}

Get a payment

One payment or receipt by id: its direction, party, amount, currency, bank account, status and journal entry. 404 when it does not exist. The release status and problems blocking a payment file are in GET /v1/payments.

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

Parameters

In Name Type Required Description
path payment_id string (uuid) yes Payment id, as returned by POST /v1/payments or GET /v1/payments.

Example request

curl "$ERP_URL/v1/payments/3fa85f64-5717-4562-b3fc-2c963f66afa6" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK PaymentOut
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",
  "direction": "string",
  "party_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "number": "string",
  "payment_date": "2026-09-21",
  "currency": "string",
  "amount": "string",
  "bank_account_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "reference": "string",
  "status": "string",
  "journal_entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "reversal_entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}

POST /v1/payments/{payment_id}/refund

Pay back an amount on account

Pay back part or all of what a posted payment keeps on account: a customer's overpayment paid back to the customer, or an advance paid to a vendor that the vendor pays back. The refund is a payment the other way (outgoing to the customer, incoming from the vendor) whose entry relieves the payment's line on account at the share of what it booked, the difference to the bank at the refund's rate being realised FX, so the amount on account shrinks in the aging, the statement and the balances by what was paid back. It goes through the approval policy (submit.policy); waiting, it reserves its amount. It is reversed like any payment (POST /v1/payments/{payment_id}/reverse), and the payment it pays back is not reversed while it stands (payment_on_account_refunded).

Refused with 422: more than is left on account (more_than_left_to_apply), dated before the payment or its latest application or refund (application_before_document, application_before_settlement), a refund received dated after today (receipt_in_future), a payment with nothing on account (nothing_to_apply) or one that is itself a refund kept on account, which is applied to the credit note it pays instead (refund_not_on_account); 409 when a reversal of the payment waits or the period is closed; 404 for an unknown payment.

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

Parameters

In Name Type Required Description
path payment_id string (uuid) yes Payment id, as returned by POST /v1/payments or GET /v1/payments.

Request body

application/json (required): OnAccountRefundInput

Field Type Required Description
payment_date string (date) yes Value date of the refund (ISO 8601), on or after the payment it pays back and its latest application, in an open period. A refund received (from a vendor) is not dated after today (receipt_in_future), nor is one paid (payment_in_future).
amount decimal string yes Amount paid back, in the payment's currency: at most what is left on account (more_than_left_to_apply). (greater than 0)
bank_account string or null GL bank account code; default: the main bank account for the currency.
reference string or null Free text reference.
executed boolean A refund paid out only: true when the bank already executed it; it is booked on the bank account at once and goes into no payment file. Default false: it awaits execution on the payments-in-transit account until its bank line is matched (ADR-0060). (default false)

Example request

curl -X POST "$ERP_URL/v1/payments/3fa85f64-5717-4562-b3fc-2c963f66afa6/refund" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "amount": "185.78",
  "payment_date": "2026-10-11",
  "reference": "Refund"
}'

Responses

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

{
  "payment_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "status": "string",
  "fx_difference": "string",
  "discount": "0.00",
  "in_transit": false,
  "submit": {
    "entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "status": "string",
    "number": "string",
    "policy": {
      "decision": "allow",
      "reason": "string",
      "rule_id": "string",
      "table_id": "string"
    },
    "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "reason": "string"
  },
  "warnings": [
    "string"
  ],
  "warning_reasons": [
    {
      "words": "string",
      "code": "string",
      "details": {},
      "text": "string"
    }
  ]
}

POST /v1/payments/{payment_id}/reverse

Reverse a payment or receipt

Reverse a posted payment or receipt: an entry of its own, dated on (default today, or the payment date of a payment scheduled later; not before the payment, in an open period), undoes the payment's entry line by line (bank, receivables or payables at the documents' historical rates, cash discount with its VAT correction, realised FX difference), so the books are as before it to the cent. The reason is required (at most 500 characters) and kept on the entry and in the audit trail.

The reversal goes through the approval policy as the payment did (post, with its source and amount). status reversed: it is posted, the payment and its allocations are reversed and the invoices, bills or credit notes it settled are open again by what it settled. status posted: the reversal waits for a second person (reversal.approval_id, decided with POST /v1/approvals/{approval_id}/approve, four eyes) and the payment stands until then. A reversal asked by an agent, and one of a payment released in a payment file (released_in: make sure the bank did not execute it), always waits for a person.

Refused with 409: the payment is not posted (one waiting for approval is rejected instead), already reversed or its reversal already waits; it is matched to a bank statement line (undo the match on that line first, POST /v1/bank-lines/{line_id}/unmatch, which reverses the payment the match recorded); the period of the date is closed. 422: no period covers the date, the date is before the payment's, or the reason is missing. 404: unknown payment.

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

Parameters

In Name Type Required Description
path payment_id string (uuid) yes Payment id, as returned by POST /v1/payments or GET /v1/payments.

Request body

application/json (required): PaymentReverseRequest

Field Type Required Description
on string (date) or null Date of the reversal entry, ISO 8601: not before the payment date, in an open period. Default: today, or the payment date when it is later (a scheduled outgoing payment).
reason string yes Why the payment is reversed (required, at most 500 characters): on the reversal entry, in the approval request and in the audit trail. (min length 1; max length 500)

Example request

curl -X POST "$ERP_URL/v1/payments/3fa85f64-5717-4562-b3fc-2c963f66afa6/reverse" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "on": "2026-10-10",
  "reason": "Booked twice"
}'

Responses

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

{
  "payment_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "status": "posted",
  "reversal": {
    "entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "status": "string",
    "number": "string",
    "policy": {
      "decision": "allow",
      "reason": "string",
      "rule_id": "string",
      "table_id": "string"
    },
    "approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "reason": "string"
  },
  "released_in": "string"
}

Schemas

ApplicationInput

Field Type Required Description
entity string yes Code (or id) of the entity, e.g. CH01.
payment string or null Id or number of a posted payment or receipt with an amount on account to apply. Give this or credit_note.
credit_note string or null Id or number of a posted credit note with an open amount to apply. Give this or payment.
application_date string (date) yes The day the application takes effect (ISO 8601): on or after the payment or credit note and every document it settles, in an open period. The aging and the statement count it from this day.
allocations array of ApplyTo yes The invoices or bills it settles, each an open posted document of the same customer or vendor, with the amount applied (and, for a document in another currency, what it settles there). Together at most what is left on account (or open on the credit note). (min items 1)

ApplicationResult

Field Type Required Description
source "credit_note" | "payment" yes What was applied: payment or credit_note.
source_id string (uuid) yes Id of the payment or credit note applied.
allocations array of string (uuid) yes Ids of the new allocations, one per document.
status string yes posted, or pending_approval when the approval policy needs a second person: until then the amounts are reserved, on both sides.
fx_difference string yes Realised FX gain (positive) or loss (negative) booked, in the functional currency: the payment's or credit note's carrying amount against the documents'. 0 without a currency difference.
left string yes What is left to apply afterwards, in its currency.
submit SubmitResult yes How the application's entry was submitted: policy, entry id and approval_id.

ApplyTo

Field Type Required Description
document string yes Id or number of the invoice or bill to settle.
amount decimal string yes Amount applied to it, in the currency of the payment or credit note applied. (greater than 0)
document_amount decimal string or null What it settles on the document, in the document's currency. Only for a document in another currency than the payment or credit note applied; default: amount converted at the application date's rate. The difference is booked as realised FX gain or loss. (greater than 0)

BankBalance

Field Type Required Description
currency string yes ISO 4217 currency of the bills.
account string yes Code of the bank account they are paid from.
account_currency string yes The currency the account holds.
balance string yes Its book balance on the payment date (posted entries), less the outgoing payments from it the bank has not executed yet (ADR-0060), in account_currency.

CurrencyTotal

Field Type Required Description
bills integer yes Number of bills.
amount string yes Amount to pay in total, after discounts.
discount string yes Cash discounts taken in total.

OnAccountRefundInput

Paying back an amount kept on account: a customer's overpayment, or a vendor's refund of an advance paid to it.

Field Type Required Description
payment_date string (date) yes Value date of the refund (ISO 8601), on or after the payment it pays back and its latest application, in an open period. A refund received (from a vendor) is not dated after today (receipt_in_future), nor is one paid (payment_in_future).
amount decimal string yes Amount paid back, in the payment's currency: at most what is left on account (more_than_left_to_apply). (greater than 0)
bank_account string or null GL bank account code; default: the main bank account for the currency.
reference string or null Free text reference.
executed boolean A refund paid out only: true when the bank already executed it; it is booked on the bank account at once and goes into no payment file. Default false: it awaits execution on the payments-in-transit account until its bank line is matched (ADR-0060). (default false)

OpenCredit

A payment's amount on account, or a credit note's open amount, that can still be applied.

Field Type Required Description
source "credit_note" | "payment" yes payment (an amount on account) or credit_note.
id string (uuid) yes Id of the payment or credit note.
number string or null yes Its number, e.g. RCPT-2026-000004 or CN-2026-000003.
kind string yes The payment's direction (incoming, outgoing) or the credit note's kind (sales_credit_note, purchase_credit_note).
party_id string (uuid) yes Id of the customer or vendor.
party_code string yes Code of the customer or vendor.
party string yes Name of the customer or vendor.
date string (date) yes Payment date, or credit note date.
currency string yes ISO 4217 currency of the amounts.
amount string yes The amount kept on account when the payment was recorded, or the credit note's total.
open string yes What is left to apply now (applications waiting for approval reserve theirs).

PaymentInput

Field Type Required Description
entity string yes Code (or id) of the entity paying or receiving, e.g. CH01.
direction "incoming" | "outgoing" yes incoming: a receipt from a customer; outgoing: a payment to a vendor.
party string yes Customer or vendor code (or id), e.g. C-DE or V-BM.
payment_date string (date) or null Value date of the payment (ISO 8601); default today where the company is. The exchange rate of this day gives the realised FX difference. The fiscal period must be open. A receipt (incoming) is not dated after today (receipt_in_future), nor is a payment made (payment_in_future: a payment file asks the bank for a later execution date); neither is dated before a document it settles (payment_before_document).
amount decimal string yes Total amount paid, a decimal string such as 1500.00; it must equal the sum of the allocation amounts and on_account (cash discounts are on top of it). (greater than 0)
currency string or null ISO 4217 code of the payment; default: the party's currency. A document in another currency is settled too: its allocation names what it settles in the document's currency (document_amount). (pattern ^[A-Z]{3}$)
bank_account string or null GL bank account code; default: the main bank account (role 'bank') when it holds the payment's currency, else the first active bank account in that currency, else the main one. A receipt collected by a payment provider (Shopify Payments) names the provider's balance (role 'provider_balance'), never a default.
reference string or null Free text reference, e.g. the bill number or a bank reference.
allocations array of AllocationInput-Input The documents the payment settles: each allocation names a posted document of the party and the amount applied. May be empty when the whole amount is on_account.
on_account decimal string The part of the amount allocated to no document, e.g. an overpayment or an advance: it stays on the party's account (an open item of the party in the aging and the statement) until it is applied to an invoice or bill with POST /v1/applications. Default 0: the allocations take the whole amount. (min 0; default "0")
bank_line_id string (uuid) or null Id of the bank statement line the payment records, when it is entered from a bank statement; such a payment counts as already executed and is not put into a payment file.
party_kind "customer" | "vendor" or null Defaults to customer for incoming, vendor for outgoing; set it for refunds.
executed boolean Outgoing payments only: true when the bank already executed the payment (paid in e-banking, by card or in cash): it is booked on the bank account at once and goes into no payment file. Default false: the payment awaits execution by the bank (a payment file, or a transfer still to be made) and is booked on the payments-in-transit account (role payments_in_transit) until the bank statement line that shows it is matched, which moves it to the bank account (ADR-0060). A payment recorded from a bank line (bank_line_id) and a receipt always go to the bank account. (default false)

PaymentOut

Field Type Required Description
id string (uuid) yes Id of the payment.
direction string yes incoming (receipt) or outgoing (payment).
party_id string (uuid) yes Id of the customer or vendor.
number string or null yes Payment number such as PAY-2026-000001 or RCPT-2026-000001, assigned when it is posted; null before.
payment_date string (date) yes Value date.
currency string yes ISO 4217 currency of the payment.
amount string yes Amount paid, in the payment currency.
bank_account_id string (uuid) yes Id of the GL bank account.
reference string or null yes Free text reference.
status string yes draft, pending_approval, posted, rejected or reversed (its reversal is posted and the documents it settled are open again).
journal_entry_id string (uuid) or null yes Id of the payment's journal entry.
reversal_entry_id string (uuid) or null Id of the entry that reverses the payment's entry, once a reversal was asked for (POST /v1/payments/{payment_id}/reverse): posted when the payment is reversed, else waiting for approval (or rejected); null before.

PaymentProposal

Field Type Required Description
entity string yes Code of the entity.
payment_date string (date) yes The day the proposal books the payments on.
due_until string (date) yes Bills due on or before this date are proposed.
take_discounts boolean yes Whether cash discounts are deducted.
lines array of ProposalLine yes The proposed bills, ordered by vendor and due date.
totals_by_currency map of CurrencyTotal yes Bills, amount and discount per currency.
skipped array of SkippedBill Bills that would be due but are left out, with why (code): bill_payment_blocked (a purchase order variance waits for approval), bill_settled_elsewhere (another process settles it: a purchase on a company card, which the card issuer collects), party_blocked, party_inactive or party_block_waiting.
bank_balances array of BankBalance Per currency of the proposed bills, the bank account the run would pay from and its book balance on the payment date: when the bills chosen add up to more (in the account's currency), the run takes it below zero in the books and says so in its warnings; it is not refused.

PaymentReversalResult

Field Type Required Description
payment_id string (uuid) yes Id of the payment.
status "posted" | "reversed" yes reversed: the reversal is posted, the documents the payment settled are open again; posted: the reversal waits for a second person (reversal.approval_id) and the payment stands until it is approved.
reversal SubmitResult yes The reversal entry's submission: policy, entry id, its number once posted and the approval_id while it waits.
released_in string or null The message id of the payment file the payment was released in, if it was: make sure the bank did not execute it (such a reversal always waits for a second person).

PaymentReverseRequest

Field Type Required Description
on string (date) or null Date of the reversal entry, ISO 8601: not before the payment date, in an open period. Default: today, or the payment date when it is later (a scheduled outgoing payment).
reason string yes Why the payment is reversed (required, at most 500 characters): on the reversal entry, in the approval request and in the audit trail. (min length 1; max length 500)

PaymentRunInput

Field Type Required Description
payment_date string (date) yes Day the payments are booked (ISO 8601, e.g. 2026-09-30), today at the latest. The bank pays on the execution date of the payment file, which may be later but not after the cash discount period of a bill whose discount the payment takes.
bank_account string or null GL bank account code; default: per currency, as a payment's default bank account, refused when only a main account in another currency is left.
lines array of RunLine yes The reviewed proposal lines to pay, 1 to 1000 vendor bills with the amount and cash discount of each. (min items 1; max items 1000)

PaymentRunResult

Field Type Required Description
entity string yes Code of the entity.
payment_date string (date) yes Date of the payments.
payments array of RunPayment yes The payments created, one per vendor (a bill with a structured reference on its own).
posted integer yes Number of payments posted.
pending_approval integer yes Number of payments waiting for a second person.
warnings array of string What to know that did not stop the run, in English: one line per bank account the run takes below zero in the books on the payment date (the money may be there and not booked yet).
warning_reasons array of Reason The same by code (bankBalance.warning.overdrawn, with account, entity, balance, after, currency and on; overdrawn_in_transit adds in_transit when payments the bank has not executed yet count towards it), in the order of warnings.

ProposalCriteria

Field Type Required Description
payment_date string (date) yes The day the payments would be booked; cash discounts are offered while it is within their period. A preview may look ahead; the run itself is dated today at the latest, and the bank pays on the execution date chosen when the payment file is sent.
due_until string (date) or null Last payment date: bills due on or before it are proposed (default the payment date).
take_discounts boolean Deduct cash discounts still available on the payment date, and also propose bills not yet due whose discount would expire by due_until. (default true)
vendors array of string or null Vendor codes (default all).
currency string or null ISO 4217 code: propose only bills in this currency; default: all. (pattern ^[A-Z]{3}$)
bank_account string or null GL bank account code the run will pay from, as the run's bank_account; default: per currency. Only bank_balances depends on it.

ProposalLine

Field Type Required Description
document_id string (uuid) yes Id of the bill.
number string yes Number of the bill.
external_number string or null yes The vendor's invoice number.
vendor string yes Vendor code.
vendor_name string yes Name of the vendor.
currency string yes ISO 4217 currency of the bill.
document_date string (date) yes Date of the bill.
due_date string (date) yes Due date of the bill.
cash_discount_percent string or null yes Cash discount percent of the bill, if any.
cash_discount_date string (date) or null yes Last day the cash discount may be taken.
total string yes Gross total of the bill.
open string yes Open amount of the bill before the discount.
discount string yes Cash discount taken by paying on the payment date.
amount string yes Amount to pay: open less discount.
reason "cash_discount" | "due" | "overdue" yes Why it is proposed: overdue (due before the payment date), due (due by due_until) or cash_discount (not yet due, but the discount would expire).
payment_iban string or null yes The bill's payment account or the vendor's.
payment_reference string or null yes Structured reference printed on the bill, if any.
warnings array of string yes Things to review before paying, e.g. a missing IBAN or a draft vendor.
problems array of BlockerOut What would stop the payment going into a payment file (pain.001), by the same rule as POST /v1/payment-exports, e.g. payment_cross_border (currency, country): such a bill is paid in the bank's e-banking instead. Codes and details as the export's refusals.
credit_available string What the vendor has to its credit in the bill's currency: paid on account and not applied, and open credit notes (ADR-0045). Above zero, paying the bill in full would pay twice: apply the credit first (POST /v1/applications) or pay less. (default "0.00")
preselected boolean Whether to pay the bill as proposed; false while the vendor has credit (credit_available), with a warning. (default true)

RunLine

Field Type Required Description
document string yes Bill id or number.
amount decimal string yes Amount to pay. (greater than 0)
discount decimal string Cash discount taken. (min 0; default "0")

RunPayment

Field Type Required Description
payment_id string (uuid) yes Id of the payment that was created.
vendor string yes Vendor code.
vendor_name string yes Vendor name.
currency string yes ISO 4217 currency of the payment.
amount string yes Amount paid, in the payment currency.
discount string yes Cash discount taken on the bills of this payment.
documents array of string yes Numbers of the bills the payment settles.
status string yes posted, or pending_approval when the approval policy needs a second person.
approval_id string (uuid) or null yes Id of the approval request when the payment waits for approval.
entry_id string (uuid) or null Id of the payment's journal entry.

SkippedBill

Field Type Required Description
document_id string (uuid) yes Id of the bill.
number string yes Number of the bill.
vendor string yes Vendor code.
vendor_name string yes Name of the vendor.
currency string yes ISO 4217 currency of the bill.
open string yes Open amount of the bill.
code string yes Why, as listed under skipped: see the codes there.
reason string yes Why it is left out, in words.
Stabiso, the Enterprise System of Record · generated from the code and its guides · release 20b7dd5b0c4d