Intercompany
Trade between two entities of one organization: the approved relationship (with its VAT group and transfer-pricing record), the draft bill an invoice creates in the counterpart and its acceptance, loans with their interest, group dividends, the settlements, and the reconciliation of the two sides.
| Operation | Summary | Scope | Idempotency-Key |
|---|---|---|---|
GET /v1/ic/links |
List the intercompany links | read |
|
GET /v1/ic/links/{link_id} |
Get an intercompany link | read |
|
POST /v1/ic/links/{link_id}/reject |
Reject the mirror of an intercompany document | post |
|
POST /v1/ic/links/{link_id}/retry |
Make the counterpart of a link again | post |
|
GET /v1/ic/loans |
List the intercompany loans | read |
|
POST /v1/ic/loans |
Request an intercompany loan | draft |
required |
GET /v1/ic/loans/{loan_id} |
Get an intercompany loan | read |
|
POST /v1/ic/loans/{loan_id}/drawdowns |
Draw down an intercompany loan | post |
required |
POST /v1/ic/loans/{loan_id}/interest |
Accrue the interest of an intercompany loan | post |
required |
POST /v1/ic/loans/{loan_id}/repayments |
Repay an intercompany loan | post |
required |
GET /v1/ic/movements |
List the intercompany movements | read |
|
GET /v1/ic/movements/{movement_id} |
Get an intercompany movement | read |
|
GET /v1/ic/reconciliation |
Reconcile the intercompany balances | read |
|
GET /v1/ic/relationships |
List the intercompany relationships | read |
|
POST /v1/ic/relationships |
Request an intercompany relationship | draft |
required |
GET /v1/ic/relationships/{relationship_id} |
Get an intercompany relationship | read |
|
PATCH /v1/ic/relationships/{relationship_id} |
Change, suspend or resume an intercompany relationship | draft |
|
POST /v1/ic/settlements |
Settle intercompany interest or a group dividend | post |
required |
GET /v1/ic/links
List the intercompany links
The evidence that a posted invoice or credit note of one entity has a counterpart in the
other, newest first: both documents, the status, why a counterpart could not be made (error),
who posted the origin (that person does not accept the mirror), who accepted or rejected the
mirror and why. A drafted mirror is accepted like any bill: a person in the receiving entity
recodes it if needed and submits it (POST /v1/documents/{id}/submit).
| Required scope | read (admin implies every scope) |
| Operation id | list_links_v1_ic_links_get |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| query | relationship |
string (uuid) or null | Only the links of this relationship (GET /v1/ic/relationships). |
|
| query | status |
"accepted" | "drafted" | "mirror_rejected" | "pending" | "rejected" | "waiting" or null |
Only links in this state: drafted are the mirror documents waiting to be accepted, pending those whose counterpart could not be made. |
|
| query | entity |
string or null | Only links where this entity is either side. | |
| query | limit |
integer | At most this many links, newest first. (min 1; max 500; default 100) |
Example request
curl "$ERP_URL/v1/ic/links" \
-H "Authorization: Bearer $ERP_KEY"
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | array of LinkOut |
| 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)
[
{
"counter": {
"document_date": "2026-09-21",
"document_id": "7c2d6a0e-2a64-4d36-b0a3-9e5a1d6f2c02",
"entity": "DE01",
"kind": "purchase_bill",
"party_code": "IC-CH01",
"status": "draft",
"total": "10000.00"
},
"created_at": "2026-09-21T10:15:00Z",
"currency": "CHF",
"id": "e3a1f0b2-6d7c-4b8a-9c0d-1e2f3a4b5c03",
"kind": "invoice",
"net_total": "10000.00",
"origin": {
"document_date": "2026-09-21",
"document_id": "0b9b8a53-1c4e-4f3a-8f55-3f2c3b8a6d01",
"entity": "CH01",
"kind": "sales_invoice",
"number": "INV-2026-000001",
"party_code": "IC-DE01",
"status": "posted",
"total": "10000.00"
},
"origin_posted_by": {
"id": "user:alice",
"name": "Alice",
"type": "human"
},
"relationship_id": "6f1c1c1e-5a53-4a4e-9b7f-0d2f6b2b9a10",
"status": "drafted"
}
]
GET /v1/ic/links/{link_id}
Get an intercompany link
One link with its origin and counterpart documents. 404 when it does not exist or belongs to another organization.
| Required scope | read (admin implies every scope) |
| Operation id | get_link_v1_ic_links__link_id__get |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | link_id |
string (uuid) | yes | Id of the link (GET /v1/ic/links). |
Example request
curl "$ERP_URL/v1/ic/links/3fa85f64-5717-4562-b3fc-2c963f66afa6" \
-H "Authorization: Bearer $ERP_KEY"
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | LinkOut |
| 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)
{
"counter": {
"document_date": "2026-09-21",
"document_id": "7c2d6a0e-2a64-4d36-b0a3-9e5a1d6f2c02",
"entity": "DE01",
"kind": "purchase_bill",
"party_code": "IC-CH01",
"status": "draft",
"total": "10000.00"
},
"created_at": "2026-09-21T10:15:00Z",
"currency": "CHF",
"id": "e3a1f0b2-6d7c-4b8a-9c0d-1e2f3a4b5c03",
"kind": "invoice",
"net_total": "10000.00",
"origin": {
"document_date": "2026-09-21",
"document_id": "0b9b8a53-1c4e-4f3a-8f55-3f2c3b8a6d01",
"entity": "CH01",
"kind": "sales_invoice",
"number": "INV-2026-000001",
"party_code": "IC-DE01",
"status": "posted",
"total": "10000.00"
},
"origin_posted_by": {
"id": "user:alice",
"name": "Alice",
"type": "human"
},
"relationship_id": "6f1c1c1e-5a53-4a4e-9b7f-0d2f6b2b9a10",
"status": "drafted"
}
POST /v1/ic/links/{link_id}/reject
Reject the mirror of an intercompany document
The receiving entity refuses the draft: it is voided and the link becomes rejected with the
reason, which the sender sees; the sender corrects with a credit note. A difference between the
two sides that a rejected mirror leaves is unexplained in the reconciliation until then.
Humans only, and not the person who posted the origin (accept_own_ic_document). 409 for a
link whose mirror is not a draft any more.
| Required scope | post (admin implies every scope) |
| Idempotency-Key | not used |
| Operation id | reject_link_v1_ic_links__link_id__reject_post |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | link_id |
string (uuid) | yes | Id of the link (GET /v1/ic/links). |
Request body
application/json (required): RejectInput
| Field | Type | Required | Description |
|---|---|---|---|
reason |
string | yes | Why the receiving entity refuses the document; the sender sees it. (min length 3; max length 1000) |
Example request
curl -X POST "$ERP_URL/v1/ic/links/3fa85f64-5717-4562-b3fc-2c963f66afa6/reject" \
-H "Authorization: Bearer $ERP_KEY" \
-H "Content-Type: application/json" \
-d '{
"reason": "The fee was agreed at 8,000, not 10,000"
}'
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | LinkOut |
| 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)
{
"counter": {
"document_date": "2026-09-21",
"document_id": "7c2d6a0e-2a64-4d36-b0a3-9e5a1d6f2c02",
"entity": "DE01",
"kind": "purchase_bill",
"party_code": "IC-CH01",
"status": "draft",
"total": "10000.00"
},
"created_at": "2026-09-21T10:15:00Z",
"currency": "CHF",
"id": "e3a1f0b2-6d7c-4b8a-9c0d-1e2f3a4b5c03",
"kind": "invoice",
"net_total": "10000.00",
"origin": {
"document_date": "2026-09-21",
"document_id": "0b9b8a53-1c4e-4f3a-8f55-3f2c3b8a6d01",
"entity": "CH01",
"kind": "sales_invoice",
"number": "INV-2026-000001",
"party_code": "IC-DE01",
"status": "posted",
"total": "10000.00"
},
"origin_posted_by": {
"id": "user:alice",
"name": "Alice",
"type": "human"
},
"relationship_id": "6f1c1c1e-5a53-4a4e-9b7f-0d2f6b2b9a10",
"status": "drafted"
}
POST /v1/ic/links/{link_id}/retry
Make the counterpart of a link again
Repeat the construction of the counterpart for a link that is pending (its error says
why: no VAT number, a vendor number already used in the receiving entity, a missing account) or
waiting (a credit note whose invoice's mirror has been posted since). The origin stays posted
whatever happens here; the answer shows the new state. 409 for a link that is not pending or
waiting.
| Required scope | post (admin implies every scope) |
| Idempotency-Key | not used |
| Operation id | retry_link_v1_ic_links__link_id__retry_post |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | link_id |
string (uuid) | yes | Id of the link (GET /v1/ic/links). |
Example request
curl -X POST "$ERP_URL/v1/ic/links/3fa85f64-5717-4562-b3fc-2c963f66afa6/retry" \
-H "Authorization: Bearer $ERP_KEY"
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | LinkOut |
| 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)
{
"counter": {
"document_date": "2026-09-21",
"document_id": "7c2d6a0e-2a64-4d36-b0a3-9e5a1d6f2c02",
"entity": "DE01",
"kind": "purchase_bill",
"party_code": "IC-CH01",
"status": "draft",
"total": "10000.00"
},
"created_at": "2026-09-21T10:15:00Z",
"currency": "CHF",
"id": "e3a1f0b2-6d7c-4b8a-9c0d-1e2f3a4b5c03",
"kind": "invoice",
"net_total": "10000.00",
"origin": {
"document_date": "2026-09-21",
"document_id": "0b9b8a53-1c4e-4f3a-8f55-3f2c3b8a6d01",
"entity": "CH01",
"kind": "sales_invoice",
"number": "INV-2026-000001",
"party_code": "IC-DE01",
"status": "posted",
"total": "10000.00"
},
"origin_posted_by": {
"id": "user:alice",
"name": "Alice",
"type": "human"
},
"relationship_id": "6f1c1c1e-5a53-4a4e-9b7f-0d2f6b2b9a10",
"status": "drafted"
}
GET /v1/ic/loans
List the intercompany loans
The loans of the organization, oldest first, each with its terms, who requested and
approved it, the approval that waits, and what it stands at from its movements: the
principal outstanding, the day interest is accrued_through and the interest_open (accrued
and not settled). 404 for an entity that does not exist.
| Required scope | read (admin implies every scope) |
| Operation id | list_loans_v1_ic_loans_get |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| query | entity |
string or null | Only the loans this entity lends or borrows. | |
| query | status |
"active" | "closed" | "draft" or null |
Only loans in this state. | |
| query | limit |
integer | At most this many loans, oldest first. (min 1; max 500; default 200) |
Example request
curl "$ERP_URL/v1/ic/loans" \
-H "Authorization: Bearer $ERP_KEY"
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | array of LoanOut |
| 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",
"reference": "string",
"relationship_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"lender": "string",
"borrower": "string",
"currency": "string",
"facility_amount": "string",
"interest_rate_percent": "string",
"interest_basis": "string",
"day_count": "30/360",
"start_date": "2026-09-21",
"maturity_date": "2026-09-21",
"lender_bank_account": "string",
"lender_bank_balance": "string",
"lender_bank_currency": "",
"borrower_bank_account": "string",
"net_investment": true,
"status": "active",
"principal": "string",
"accrued_through": "2026-09-21",
"interest_open": "string",
"requested_by": {},
"approved_by": {},
"approved_at": "2026-09-21T09:30:00Z",
"approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"closed_at": "2026-09-21T09:30:00Z",
"created_at": "2026-09-21T09:30:00Z"
}
]
POST /v1/ic/loans
Request an intercompany loan
Ask for a loan between the two entities of an active relationship. It is written
draft and a second person approves its terms (POST /v1/approvals/{approval_id}/approve;
the policy action approve_ic_agreement, human only): the amount, the currency, the fixed
rate with its arm's-length interest_basis in words (recorded, never judged), the day count,
the dates, the two bank accounts and whether the loan is part of the net investment (IAS
21.15). The approval is bound to the terms by a digest and they never change afterwards. 409
role_missing names an account the lender (ic_loan_receivable, ic_other_receivable,
ic_interest_income) or the borrower (ic_loan_payable, ic_other_payable,
ic_interest_expense) lacks, 409 without an active relationship or for a reference in use,
422 for a bank account that is not an active asset account. Humans only. Needs an
Idempotency-Key.
| Required scope | draft (admin implies every scope) |
| Idempotency-Key | required |
| Operation id | create_loan_v1_ic_loans_post |
Request body
application/json (required): LoanInput
| Field | Type | Required | Description |
|---|---|---|---|
reference |
string | yes | The loan's reference, unique in the organization. (min length 1; max length 40) |
lender |
string | yes | Code (or id) of the entity that lends. |
borrower |
string | yes | Code (or id) of the entity that borrows. |
currency |
string or null | ISO 4217 currency of the loan. Omitted: the lender's functional currency. (min length 3; max length 3) | |
facility_amount |
decimal string | yes | The agreed amount: what may be drawn at most (a decimal string). (greater than 0) |
interest_rate_percent |
decimal string | yes | Fixed annual rate in percent, e.g. 3.0000. (min 0; max 100) |
interest_basis |
string | yes | The arm's-length basis the approvers accepted, in words (the benchmark, its source and date). Recorded, never judged. (min length 3; max length 2000) |
day_count |
"30/360" | "act/360" | "act/365" |
yes | act/360, act/365 (fixed) or 30/360 (European, 30E/360). |
start_date |
string (date) | yes | First day a drawdown may be dated. |
maturity_date |
string (date) | yes | The day the loan falls due; after the start. |
lender_bank_account |
string | yes | Code of the lender's bank account in its chart (an asset account): where drawdowns are paid from and repayments come in. |
borrower_bank_account |
string | yes | Code of the borrower's bank account in its chart (an asset account). |
net_investment |
boolean | IAS 21.15: settlement is neither planned nor likely, so the loan is part of the net investment in a foreign operation and the consolidation takes its exchange differences to the translation reserve (IAS 21.32). (default false) |
Example request
curl -X POST "$ERP_URL/v1/ic/loans" \
-H "Authorization: Bearer $ERP_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"borrower": "DE01",
"borrower_bank_account": "1010",
"currency": "EUR",
"day_count": "act/360",
"facility_amount": "500000.00",
"interest_basis": "3-month EURIBOR of 30 September 2026 plus 0.50 %, the benchmark the tax adviser documented on 25 September 2026",
"interest_rate_percent": "3.0000",
"lender": "CH01",
"lender_bank_account": "1020",
"maturity_date": "2029-09-30",
"reference": "L-2026-01",
"start_date": "2026-10-01"
}'
Responses
| Status | Meaning | Body |
|---|---|---|
| 201 | Created | LoanOut |
| 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",
"reference": "string",
"relationship_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"lender": "string",
"borrower": "string",
"currency": "string",
"facility_amount": "string",
"interest_rate_percent": "string",
"interest_basis": "string",
"day_count": "30/360",
"start_date": "2026-09-21",
"maturity_date": "2026-09-21",
"lender_bank_account": "string",
"lender_bank_balance": "string",
"lender_bank_currency": "",
"borrower_bank_account": "string",
"net_investment": true,
"status": "active",
"principal": "string",
"accrued_through": "2026-09-21",
"interest_open": "string",
"requested_by": {},
"approved_by": {},
"approved_at": "2026-09-21T09:30:00Z",
"approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"closed_at": "2026-09-21T09:30:00Z",
"created_at": "2026-09-21T09:30:00Z"
}
GET /v1/ic/loans/{loan_id}
Get an intercompany loan
One loan with its terms and what it stands at. 404 when it does not exist or belongs to another organization.
| Required scope | read (admin implies every scope) |
| Operation id | get_loan_v1_ic_loans__loan_id__get |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | loan_id |
string (uuid) | yes | Id of the loan (GET /v1/ic/loans). |
Example request
curl "$ERP_URL/v1/ic/loans/3fa85f64-5717-4562-b3fc-2c963f66afa6" \
-H "Authorization: Bearer $ERP_KEY"
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | LoanOut |
| 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",
"reference": "string",
"relationship_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"lender": "string",
"borrower": "string",
"currency": "string",
"facility_amount": "string",
"interest_rate_percent": "string",
"interest_basis": "string",
"day_count": "30/360",
"start_date": "2026-09-21",
"maturity_date": "2026-09-21",
"lender_bank_account": "string",
"lender_bank_balance": "string",
"lender_bank_currency": "",
"borrower_bank_account": "string",
"net_investment": true,
"status": "active",
"principal": "string",
"accrued_through": "2026-09-21",
"interest_open": "string",
"requested_by": {},
"approved_by": {},
"approved_at": "2026-09-21T09:30:00Z",
"approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"closed_at": "2026-09-21T09:30:00Z",
"created_at": "2026-09-21T09:30:00Z"
}
POST /v1/ic/loans/{loan_id}/drawdowns
Draw down an intercompany loan
The lender pays out: Dr ic_loan_receivable / Cr bank in the lender, Dr bank / Cr ic_loan_payable in the borrower, in the loan's currency at the ECB rate of the value date.
409 for a loan that is not active, a value date outside the start and the maturity, or an
amount beyond what is left of the facility; 409 when the date is on or before the day interest
is accrued through (accrue first, the day count would be wrong). Both entities' entries are
made in one transaction and each goes through its entity's posting policy (an entry that needs
approval waits, and the reconciliation lists it as loan_movement_missing until it posts).
A payout that takes the lender's bank account below zero in the books on the value date is
made, with a warnings line saying so and its warning_reasons by code (the money may be
there and not booked yet). Needs an Idempotency-Key.
| Required scope | post (admin implies every scope) |
| Idempotency-Key | required |
| Operation id | drawdown_v1_ic_loans__loan_id__drawdowns_post |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | loan_id |
string (uuid) | yes | Id of the loan (GET /v1/ic/loans). |
Request body
application/json (required): MovementInput
| Field | Type | Required | Description |
|---|---|---|---|
value_date |
string (date) | yes | The day the money moves; both entries are dated it. |
amount |
decimal string | yes | In the loan's currency (a decimal string). (greater than 0) |
reference |
string or null | Your reference, e.g. the bank's; optional. (max length 200) |
Example request
curl -X POST "$ERP_URL/v1/ic/loans/3fa85f64-5717-4562-b3fc-2c963f66afa6/drawdowns" \
-H "Authorization: Bearer $ERP_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"amount": "500000.00",
"value_date": "2026-10-01"
}'
Responses
| Status | Meaning | Body |
|---|---|---|
| 201 | Created | MovementOut |
| 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",
"kind": "dividend_declared",
"relationship_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"loan_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"loan_reference": "string",
"value_date": "2026-09-21",
"amount": "string",
"currency": "string",
"reference": "string",
"creditor": {
"entity": "string",
"entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"number": "string",
"status": "string"
},
"debtor": {
"entity": "string",
"entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"number": "string",
"status": "string"
},
"settles_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"detail": {},
"created_by": {},
"created_at": "2026-09-21T09:30:00Z",
"warnings": [
"string"
],
"warning_reasons": [
{
"words": "string",
"code": "string",
"details": {},
"text": "string"
}
]
}
POST /v1/ic/loans/{loan_id}/interest
Accrue the interest of an intercompany loan
Accrue the interest from the day after the last accrual (or from the start) through
through, over the principal outstanding each day, by the loan's day count, rounded half to
even once: the lender Dr ic_other_receivable / Cr ic_interest_income, the borrower Dr ic_interest_expense / Cr ic_other_payable. detail.segments shows each stretch of days with
its principal. 409 for a day on or before the last accrual, for a day in a period that has
not started yet (period_not_started), or when the interest is zero (no principal in the
period). The close check ic_interest warns while a loan with principal
outstanding is not accrued through the period's end. Both entities' entries are made in one
transaction and each goes through its entity's posting policy. Needs an
Idempotency-Key.
| Required scope | post (admin implies every scope) |
| Idempotency-Key | required |
| Operation id | accrue_v1_ic_loans__loan_id__interest_post |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | loan_id |
string (uuid) | yes | Id of the loan (GET /v1/ic/loans). |
Request body
application/json (required): InterestInput
| Field | Type | Required | Description |
|---|---|---|---|
through |
string (date) | yes | Accrue the interest up to and including this day, from the day after the last accrual (or from the first drawdown). |
Example request
curl -X POST "$ERP_URL/v1/ic/loans/3fa85f64-5717-4562-b3fc-2c963f66afa6/interest" \
-H "Authorization: Bearer $ERP_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"through": "2026-10-31"
}'
Responses
| Status | Meaning | Body |
|---|---|---|
| 201 | Created | MovementOut |
| 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",
"kind": "dividend_declared",
"relationship_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"loan_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"loan_reference": "string",
"value_date": "2026-09-21",
"amount": "string",
"currency": "string",
"reference": "string",
"creditor": {
"entity": "string",
"entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"number": "string",
"status": "string"
},
"debtor": {
"entity": "string",
"entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"number": "string",
"status": "string"
},
"settles_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"detail": {},
"created_by": {},
"created_at": "2026-09-21T09:30:00Z",
"warnings": [
"string"
],
"warning_reasons": [
{
"words": "string",
"code": "string",
"details": {},
"text": "string"
}
]
}
POST /v1/ic/loans/{loan_id}/repayments
Repay an intercompany loan
The borrower pays back principal: each side's loan balance is relieved at its carrying
amount and the bank at the ECB rate of the day; the difference is the realised exchange result
(detail.realised). The loan is closed when its principal and its open interest are both
zero. 409 for more than the principal outstanding or a date on or before the last accrual.
Both entities' entries are made in one transaction and each goes through its entity's posting
policy. One that takes the borrower's bank account below zero in the books is made, with a
warnings line. Needs an Idempotency-Key.
| Required scope | post (admin implies every scope) |
| Idempotency-Key | required |
| Operation id | repayment_v1_ic_loans__loan_id__repayments_post |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | loan_id |
string (uuid) | yes | Id of the loan (GET /v1/ic/loans). |
Request body
application/json (required): MovementInput
| Field | Type | Required | Description |
|---|---|---|---|
value_date |
string (date) | yes | The day the money moves; both entries are dated it. |
amount |
decimal string | yes | In the loan's currency (a decimal string). (greater than 0) |
reference |
string or null | Your reference, e.g. the bank's; optional. (max length 200) |
Example request
curl -X POST "$ERP_URL/v1/ic/loans/3fa85f64-5717-4562-b3fc-2c963f66afa6/repayments" \
-H "Authorization: Bearer $ERP_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"amount": "500000.00",
"value_date": "2026-10-01"
}'
Responses
| Status | Meaning | Body |
|---|---|---|
| 201 | Created | MovementOut |
| 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",
"kind": "dividend_declared",
"relationship_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"loan_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"loan_reference": "string",
"value_date": "2026-09-21",
"amount": "string",
"currency": "string",
"reference": "string",
"creditor": {
"entity": "string",
"entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"number": "string",
"status": "string"
},
"debtor": {
"entity": "string",
"entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"number": "string",
"status": "string"
},
"settles_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"detail": {},
"created_by": {},
"created_at": "2026-09-21T09:30:00Z",
"warnings": [
"string"
],
"warning_reasons": [
{
"words": "string",
"code": "string",
"details": {},
"text": "string"
}
]
}
GET /v1/ic/movements
List the intercompany movements
The drawdowns, repayments, interest accruals, settlements and declared group dividends, by
value date, each with both entities' entries and their state (a dividend's shareholder entry
stays draft until a person of the shareholder accepts it). Append-only: a movement is never
changed or deleted.
| Required scope | read (admin implies every scope) |
| Operation id | list_movements_v1_ic_movements_get |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| query | loan |
string (uuid) or null | Only the movements of this loan. | |
| query | entity |
string or null | Only movements where this entity is either side. | |
| query | kind |
"dividend_declared" | "interest_accrual" | "loan_drawdown" | "loan_repayment" | "settlement" or null |
Only movements of this kind. | |
| query | start |
string (date) or null | Value date on or after this day. | |
| query | end |
string (date) or null | Value date on or before this day. | |
| query | limit |
integer | At most this many, by value date. (min 1; max 500; default 200) |
Example request
curl "$ERP_URL/v1/ic/movements" \
-H "Authorization: Bearer $ERP_KEY"
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | array of MovementOut |
| 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",
"kind": "dividend_declared",
"relationship_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"loan_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"loan_reference": "string",
"value_date": "2026-09-21",
"amount": "string",
"currency": "string",
"reference": "string",
"creditor": {
"entity": "string",
"entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"number": "string",
"status": "string"
},
"debtor": {
"entity": "string",
"entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"number": "string",
"status": "string"
},
"settles_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"detail": {},
"created_by": {},
"created_at": "2026-09-21T09:30:00Z",
"warnings": [
"string"
],
"warning_reasons": [
{
"words": "string",
"code": "string",
"details": null,
"text": "string"
}
]
}
]
GET /v1/ic/movements/{movement_id}
Get an intercompany movement
One movement with both entries. 404 when it does not exist or belongs to another organization.
| Required scope | read (admin implies every scope) |
| Operation id | get_movement_v1_ic_movements__movement_id__get |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | movement_id |
string (uuid) | yes | Id of the movement (GET /v1/ic/movements). |
Example request
curl "$ERP_URL/v1/ic/movements/3fa85f64-5717-4562-b3fc-2c963f66afa6" \
-H "Authorization: Bearer $ERP_KEY"
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | MovementOut |
| 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",
"kind": "dividend_declared",
"relationship_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"loan_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"loan_reference": "string",
"value_date": "2026-09-21",
"amount": "string",
"currency": "string",
"reference": "string",
"creditor": {
"entity": "string",
"entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"number": "string",
"status": "string"
},
"debtor": {
"entity": "string",
"entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"number": "string",
"status": "string"
},
"settles_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"detail": {},
"created_by": {},
"created_at": "2026-09-21T09:30:00Z",
"warnings": [
"string"
],
"warning_reasons": [
{
"words": "string",
"code": "string",
"details": {},
"text": "string"
}
]
}
GET /v1/ic/reconciliation
Reconcile the intercompany balances
For each relationship and each currency of its open items, what the two entities hold
towards each other in the document currency (so the FX revaluation cannot disturb it):
a_receivable, a_payable, b_receivable, b_payable, the nets and difference = a_net + b_net, zero when both sides agree. The same figures per link and per group document
nobody linked, each with a reason: timing reasons (mirror_missing, mirror_draft,
mirror_pending_approval, payment_in_transit, cutoff) are explained and the counterpart's
to resolve; mirror_rejected, unlinked_document and amount_differs are unexplained. The
carrying amounts in each functional currency and the difference converted to the tolerance
currency at the ECB rate of the day are for information; the tolerance applies to that figure.
status is the result the close check ic_reconciled takes: pass, warn (timing items
only) or fail (a part is unexplained). Open means what the books hold: the posted payments
and credit notes up to the day.
| Required scope | read (admin implies every scope) |
| Operation id | reconciliation_v1_ic_reconciliation_get |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| query | as_of |
string (date) | yes | The day the open items are read as of, ISO 8601. |
| query | relationship |
string (uuid) or null | Only this relationship; default: every relationship that is not pending. | |
| query | entity |
string or null | Only the relationships of this entity. |
Example request
curl "$ERP_URL/v1/ic/reconciliation?as_of=2026-09-30" \
-H "Authorization: Bearer $ERP_KEY"
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | Reconciliation |
| 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)
{
"as_of": "2026-09-30",
"relationships": [
{
"carrying": [
{
"balance": "10000.00",
"entity": "CH01",
"functional_currency": "CHF"
},
{
"balance": "0.00",
"entity": "DE01",
"functional_currency": "EUR"
}
],
"currencies": [
{
"a_net": "10000.00",
"a_payable": "0.00",
"a_receivable": "10000.00",
"b_net": "0.00",
"b_payable": "0.00",
"b_receivable": "0.00",
"currency": "CHF",
"difference": "10000.00"
}
],
"detail": "1 item differs, all timing: the counterpart books its part",
"difference_in_tolerance_currency": "10000.00",
"entity_a": "CH01",
"entity_b": "DE01",
"items": [
{
"counter": {
"document_date": "2026-09-21",
"document_id": "7c2d6a0e-2a64-4d36-b0a3-9e5a1d6f2c02",
"entity": "DE01",
"kind": "purchase_bill",
"party_code": "IC-CH01",
"status": "draft",
"total": "10000.00"
},
"counter_open": "0.00",
"currency": "CHF",
"difference": "10000.00",
"explained": true,
"link_id": "e3a1f0b2-6d7c-4b8a-9c0d-1e2f3a4b5c03",
"origin": {
"document_date": "2026-09-21",
"document_id": "0b9b8a53-1c4e-4f3a-8f55-3f2c3b8a6d01",
"entity": "CH01",
"kind": "sales_invoice",
"number": "INV-2026-000001",
"party_code": "IC-DE01",
"status": "posted",
"total": "10000.00"
},
"origin_open": "10000.00",
"reason": "mirror_draft"
}
],
"relationship_id": "6f1c1c1e-5a53-4a4e-9b7f-0d2f6b2b9a10",
"status": "warn",
"tolerance_amount": "1.00",
"tolerance_currency": "CHF",
"unexplained_in_tolerance_currency": "0.00"
}
]
}
GET /v1/ic/relationships
List the intercompany relationships
The relationships of the organization, oldest first, each with its terms, who requested
and approved them, the approval that waits (approval_id), the four group parties, and the
counts the Intercompany page shows: open_mirrors (drafts waiting to be accepted),
not_made (counterparts that could not be made) and rejected_mirrors; each is the number of
links GET /v1/ic/links lists for that status. 404 for an entity that does not exist.
| Required scope | read (admin implies every scope) |
| Operation id | list_relationships_v1_ic_relationships_get |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| query | status |
"active" | "pending" | "suspended" or null |
Only relationships in this state. | |
| query | entity |
string or null | Only the relationships of this entity (code or id), on either side. | |
| query | limit |
integer | At most this many relationships, oldest first. (min 1; max 500; default 200) |
Example request
curl "$ERP_URL/v1/ic/relationships" \
-H "Authorization: Bearer $ERP_KEY"
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | array of RelationshipOut |
| 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)
[
{
"approved_at": "2026-09-01T09:30:00Z",
"approved_by": {
"id": "user:bob",
"name": "Bob",
"type": "human"
},
"created_at": "2026-09-01T09:00:00Z",
"entity_a": "CH01",
"entity_a_name": "Demo AG",
"entity_b": "DE01",
"entity_b_name": "Demo GmbH",
"id": "6f1c1c1e-5a53-4a4e-9b7f-0d2f6b2b9a10",
"markup_percent": "5",
"mirror_mode": "draft",
"not_made": 0,
"open_mirrors": 1,
"parties": [
{
"code": "IC-DE01",
"entity": "CH01",
"kind": "customer",
"party_id": "1a2b3c4d-0000-4000-8000-000000000001",
"status": "active"
},
{
"code": "IC-CH01",
"entity": "DE01",
"kind": "vendor",
"party_id": "1a2b3c4d-0000-4000-8000-000000000002",
"status": "active"
}
],
"pricing_basis": "Cost plus 5 % on the cost of the shared services, benchmark study of 2026-06-30 (median of 12 comparable service providers)",
"pricing_documented_on": "2026-06-30",
"pricing_method": "cost_plus",
"rejected_mirrors": 0,
"requested_by": {
"id": "user:alice",
"name": "Alice",
"type": "human"
},
"status": "active",
"terms_digest": "9d1f3c0b5e7a4c2f8b6d0a1e3c5f7b9d2a4c6e8f0b1d3f5a7c9e1b3d5f7a9c0e",
"tolerance_amount": "1.00",
"tolerance_currency": "CHF",
"vat_group": "none"
}
]
POST /v1/ic/relationships
Request an intercompany relationship
Ask for intercompany trade between two entities of the organization. The relationship is
written pending and a second person approves its terms (POST /v1/approvals/{approval_id}/approve; the approver is never the requester): the mirror mode, the
tolerance of the reconciliation, the VAT group and the transfer-pricing record (method,
mark-up, the basis in words, the date of the documentation), which the approvers see before
they decide; the ERP records it and never judges a price. The approval is bound to those terms
by a digest: changing any of them later is a new request. On approval, in the same
transaction, the relationship becomes active and each entity gets a customer and a vendor that
is the other entity (code IC-<code>), active at once, with name, address, VAT number and
bank accounts read from the other entity's record. Refused with 409 role_missing while an
entity has no account with the role ic_ar_control or ic_ap_control (the answer names the
entity, the role and the code its chart template suggests), 409 when the pair already has a
relationship, and 422 for a VAT group across the border or without a start date and
reference, a cost_plus without mark-up or an empty pricing basis. Humans only: the policy
action approve_ic_relationship denies agents. Needs an Idempotency-Key.
| Required scope | draft (admin implies every scope) |
| Idempotency-Key | required |
| Operation id | create_relationship_v1_ic_relationships_post |
Request body
application/json (required): RelationshipInput
| Field | Type | Required | Description |
|---|---|---|---|
mirror_mode |
"draft" | "post" |
draft (default): the document made in the counterpart is a draft that a person there accepts. post: the system posts it at once under the system policy, a standing flow the approval authorises (a monthly management fee); never the default. (default "draft") |
|
tolerance_amount |
decimal string | The difference the reconciliation counts as agreed: rounding only, in tolerance_currency. Default 1.00. (min 0; default "1") |
|
tolerance_currency |
string or null | ISO 4217 currency of the tolerance. Default: the functional currency of entity_a as named in the request. (pattern ^[A-Z]{3}$) |
|
vat_group |
"ch_vat_group" | "de_organschaft" | "none" |
none (default), ch_vat_group (a Swiss VAT group, Art. 13 MWSTG: two Swiss entities) or de_organschaft (a German tax group, § 2 para. 2 no. 2 UStG: two German entities). From vat_group_from the supplies between the two are outside the scope of VAT (vat_scope outside, reason vat_group or organschaft) and no VAT report or return has them. Never between a Swiss and a German entity. (default "none") |
|
vat_group_from |
string (date) or null | The date from which the VAT group applies (a Swiss group starts at the beginning of a tax period, Art. 13 para. 2 MWSTG); required with a VAT group, refused without one. Documents dated before it carry VAT as usual. | |
vat_group_reference |
string or null | The registration or documentation of the group (a notice of the tax authority, the Organträger's confirmation); required with a VAT group. (max length 500) | |
pricing_method |
"cost_plus" | "cup" | "other" | "profit_split" | "resale_price" | "tnmm" |
yes | The transfer-pricing method the approvers accepted: cup (comparable uncontrolled price), resale_price, cost_plus, tnmm (transactional net margin), profit_split or other. The system records it and never judges a price. |
markup_percent |
decimal string or null | The mark-up in percent where the method has one; required for cost_plus. (min 0; max 1000) |
|
pricing_basis |
string | yes | The basis in words: the benchmark or study and its date. Mandatory: an approval without it is refused (§ 1 para. 1 AStG, OECD Model Convention Art. 9). (min length 3; max length 2000) |
pricing_documented_on |
string (date) | yes | The date the documentation of the prices was made (§ 90 para. 3 AO). |
entity_a |
string | yes | Code (or id) of one entity of the pair, e.g. CH01. |
entity_b |
string | yes | Code (or id) of the other entity, e.g. DE01. |
Example request
curl -X POST "$ERP_URL/v1/ic/relationships" \
-H "Authorization: Bearer $ERP_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"entity_a": "CH01",
"entity_b": "DE01",
"markup_percent": "5",
"mirror_mode": "draft",
"pricing_basis": "Cost plus 5 % on the cost of the shared services, benchmark study of 2026-06-30 (median of 12 comparable service providers)",
"pricing_documented_on": "2026-06-30",
"pricing_method": "cost_plus",
"tolerance_amount": "1.00",
"tolerance_currency": "CHF",
"vat_group": "none"
}'
Responses
| Status | Meaning | Body |
|---|---|---|
| 201 | Created | RelationshipOut |
| 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)
{
"approved_at": "2026-09-01T09:30:00Z",
"approved_by": {
"id": "user:bob",
"name": "Bob",
"type": "human"
},
"created_at": "2026-09-01T09:00:00Z",
"entity_a": "CH01",
"entity_a_name": "Demo AG",
"entity_b": "DE01",
"entity_b_name": "Demo GmbH",
"id": "6f1c1c1e-5a53-4a4e-9b7f-0d2f6b2b9a10",
"markup_percent": "5",
"mirror_mode": "draft",
"not_made": 0,
"open_mirrors": 1,
"parties": [
{
"code": "IC-DE01",
"entity": "CH01",
"kind": "customer",
"party_id": "1a2b3c4d-0000-4000-8000-000000000001",
"status": "active"
},
{
"code": "IC-CH01",
"entity": "DE01",
"kind": "vendor",
"party_id": "1a2b3c4d-0000-4000-8000-000000000002",
"status": "active"
}
],
"pricing_basis": "Cost plus 5 % on the cost of the shared services, benchmark study of 2026-06-30 (median of 12 comparable service providers)",
"pricing_documented_on": "2026-06-30",
"pricing_method": "cost_plus",
"rejected_mirrors": 0,
"requested_by": {
"id": "user:alice",
"name": "Alice",
"type": "human"
},
"status": "active",
"terms_digest": "9d1f3c0b5e7a4c2f8b6d0a1e3c5f7b9d2a4c6e8f0b1d3f5a7c9e1b3d5f7a9c0e",
"tolerance_amount": "1.00",
"tolerance_currency": "CHF",
"vat_group": "none"
}
GET /v1/ic/relationships/{relationship_id}
Get an intercompany relationship
One relationship with its terms, the transfer-pricing record, the approval that waits and a
change of terms that waits (pending_terms), and its group parties. 404 when it does not
exist or belongs to another organization.
| Required scope | read (admin implies every scope) |
| Operation id | get_relationship_v1_ic_relationships__relationship_id__get |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | relationship_id |
string (uuid) | yes | Id of the relationship (GET /v1/ic/relationships). |
Example request
curl "$ERP_URL/v1/ic/relationships/3fa85f64-5717-4562-b3fc-2c963f66afa6" \
-H "Authorization: Bearer $ERP_KEY"
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | RelationshipOut |
| 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)
{
"approved_at": "2026-09-01T09:30:00Z",
"approved_by": {
"id": "user:bob",
"name": "Bob",
"type": "human"
},
"created_at": "2026-09-01T09:00:00Z",
"entity_a": "CH01",
"entity_a_name": "Demo AG",
"entity_b": "DE01",
"entity_b_name": "Demo GmbH",
"id": "6f1c1c1e-5a53-4a4e-9b7f-0d2f6b2b9a10",
"markup_percent": "5",
"mirror_mode": "draft",
"not_made": 0,
"open_mirrors": 1,
"parties": [
{
"code": "IC-DE01",
"entity": "CH01",
"kind": "customer",
"party_id": "1a2b3c4d-0000-4000-8000-000000000001",
"status": "active"
},
{
"code": "IC-CH01",
"entity": "DE01",
"kind": "vendor",
"party_id": "1a2b3c4d-0000-4000-8000-000000000002",
"status": "active"
}
],
"pricing_basis": "Cost plus 5 % on the cost of the shared services, benchmark study of 2026-06-30 (median of 12 comparable service providers)",
"pricing_documented_on": "2026-06-30",
"pricing_method": "cost_plus",
"rejected_mirrors": 0,
"requested_by": {
"id": "user:alice",
"name": "Alice",
"type": "human"
},
"status": "active",
"terms_digest": "9d1f3c0b5e7a4c2f8b6d0a1e3c5f7b9d2a4c6e8f0b1d3f5a7c9e1b3d5f7a9c0e",
"tolerance_amount": "1.00",
"tolerance_currency": "CHF",
"vat_group": "none"
}
PATCH /v1/ic/relationships/{relationship_id}
Change, suspend or resume an intercompany relationship
Send one kind of change. status: suspended (with a reason) stops new intercompany
postings at once, one person; the open items stay and settle normally. status: active on
a suspended relationship, and new terms (mirror mode, tolerance, VAT group, pricing
record), are approval requests: the terms in force stay until a second person approves, and the
answer's approval_id names the request (the approver sees the pricing record again). A
relationship that was never approved takes new terms at once and asks again; after a
rejection any PATCH (even {}, the terms unchanged) asks again.
refresh_parties alone reads the name, address, VAT number, country and bank accounts of
the two entities again into their four group parties (which are not edited by hand: a payment
to a group entity goes only to a bank account registered for it). 409 while a request about
the relationship already waits, for a change that changes nothing and for a status the
relationship cannot move to; 422 for terms that are not coherent. Humans only.
| Required scope | draft (admin implies every scope) |
| Idempotency-Key | not used |
| Operation id | update_relationship_v1_ic_relationships__relationship_id__patch |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | relationship_id |
string (uuid) | yes | Id of the relationship (GET /v1/ic/relationships). |
Request body
application/json (required): RelationshipUpdate
| Field | Type | Required | Description |
|---|---|---|---|
status |
"active" | "suspended" or null |
suspended stops new intercompany postings at once (one person, with a reason); open items stay and settle normally. active on a suspended relationship asks a second person to approve resuming. |
|
mirror_mode |
"draft" | "post" or null |
New mirror mode. | |
tolerance_amount |
decimal string or null | New tolerance. (min 0) | |
tolerance_currency |
string or null | New tolerance currency. (pattern ^[A-Z]{3}$) |
|
vat_group |
"ch_vat_group" | "de_organschaft" | "none" or null |
New VAT group. | |
vat_group_from |
string (date) or null | New VAT group start date. | |
vat_group_reference |
string or null | New VAT group reference. (max length 500) | |
pricing_method |
"cost_plus" | "cup" | "other" | "profit_split" | "resale_price" | "tnmm" or null |
New method. | |
markup_percent |
decimal string or null | New mark-up. (min 0; max 1000) | |
pricing_basis |
string or null | New pricing basis. (min length 3; max length 2000) | |
pricing_documented_on |
string (date) or null | New date of the documentation. | |
refresh_parties |
boolean | Read the name, address, VAT number, country and bank accounts of the two entities again into their four customer and vendor records, which are not edited by hand. Alone: it changes no terms. (default false) |
|
reason |
string or null | Why: required to suspend, kept with a change of terms in the audit trail. (min length 3; max length 1000) |
Example request
curl -X PATCH "$ERP_URL/v1/ic/relationships/3fa85f64-5717-4562-b3fc-2c963f66afa6" \
-H "Authorization: Bearer $ERP_KEY" \
-H "Content-Type: application/json" \
-d '{
"reason": "Entity DE01 is being sold",
"status": "suspended"
}'
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | RelationshipOut |
| 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)
{
"approved_at": "2026-09-01T09:30:00Z",
"approved_by": {
"id": "user:bob",
"name": "Bob",
"type": "human"
},
"created_at": "2026-09-01T09:00:00Z",
"entity_a": "CH01",
"entity_a_name": "Demo AG",
"entity_b": "DE01",
"entity_b_name": "Demo GmbH",
"id": "6f1c1c1e-5a53-4a4e-9b7f-0d2f6b2b9a10",
"markup_percent": "5",
"mirror_mode": "draft",
"not_made": 0,
"open_mirrors": 1,
"parties": [
{
"code": "IC-DE01",
"entity": "CH01",
"kind": "customer",
"party_id": "1a2b3c4d-0000-4000-8000-000000000001",
"status": "active"
},
{
"code": "IC-CH01",
"entity": "DE01",
"kind": "vendor",
"party_id": "1a2b3c4d-0000-4000-8000-000000000002",
"status": "active"
}
],
"pricing_basis": "Cost plus 5 % on the cost of the shared services, benchmark study of 2026-06-30 (median of 12 comparable service providers)",
"pricing_documented_on": "2026-06-30",
"pricing_method": "cost_plus",
"rejected_mirrors": 0,
"requested_by": {
"id": "user:alice",
"name": "Alice",
"type": "human"
},
"status": "active",
"terms_digest": "9d1f3c0b5e7a4c2f8b6d0a1e3c5f7b9d2a4c6e8f0b1d3f5a7c9e1b3d5f7a9c0e",
"tolerance_amount": "1.00",
"tolerance_currency": "CHF",
"vat_group": "none"
}
POST /v1/ic/settlements
Settle intercompany interest or a group dividend
Pay accrued interest of a loan, or a declared group dividend (the id of its
dividend_declared movement): the debtor Dr ic_other_payable / Cr bank, the creditor Dr bank / Cr ic_other_receivable, each balance relieved at its carrying amount and the bank at
the ECB rate of the day. The bank accounts default to the loan's (for a dividend, the
accounts with the role bank). 409 for more than is open, or a dividend whose shareholder
has not accepted its entry yet. Both entities' entries are made in one transaction and each
goes through its entity's posting policy. One that takes the debtor's bank account below zero
in the books is made, with a warnings line. Needs an Idempotency-Key.
| Required scope | post (admin implies every scope) |
| Idempotency-Key | required |
| Operation id | settle_v1_ic_settlements_post |
Request body
application/json (required): SettlementInput
| Field | Type | Required | Description |
|---|---|---|---|
loan |
string (uuid) or null | Settle the loan's accrued interest; or name a dividend. |
|
dividend |
string (uuid) or null | Settle a declared group dividend: the id of its dividend_declared movement. |
|
value_date |
string (date) | yes | The day of the payment. |
amount |
decimal string | yes | In the currency of what is settled; at most what is open. (greater than 0) |
payer_bank_account |
string or null | The paying entity's bank account code; default the loan's (for a dividend the account with the role bank). |
|
payee_bank_account |
string or null | The receiving entity's bank account code; default as above. | |
reference |
string or null | Your reference. (max length 200) |
Example request
curl -X POST "$ERP_URL/v1/ic/settlements" \
-H "Authorization: Bearer $ERP_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"amount": "1250.00",
"loan": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"value_date": "2026-11-05"
}'
Responses
| Status | Meaning | Body |
|---|---|---|
| 201 | Created | MovementOut |
| 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",
"kind": "dividend_declared",
"relationship_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"loan_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"loan_reference": "string",
"value_date": "2026-09-21",
"amount": "string",
"currency": "string",
"reference": "string",
"creditor": {
"entity": "string",
"entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"number": "string",
"status": "string"
},
"debtor": {
"entity": "string",
"entry_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"number": "string",
"status": "string"
},
"settles_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"detail": {},
"created_by": {},
"created_at": "2026-09-21T09:30:00Z",
"warnings": [
"string"
],
"warning_reasons": [
{
"words": "string",
"code": "string",
"details": {},
"text": "string"
}
]
}
Schemas
BalanceRow
A loan, its accrued interest or a declared group dividend, and what the two sides hold of it (ADR-0025, section 6).
| Field | Type | Required | Description |
|---|---|---|---|
kind |
"dividend" | "interest" | "loan" |
yes | loan (the principal), interest (accrued and not paid) or dividend (declared and not paid). |
item_id |
string (uuid) | yes | The loan (GET /v1/ic/loans), or the dividend's dividend_declared movement. |
reference |
string | yes | The loan's or the dividend's reference. |
currency |
string | yes | Currency of the item. |
a_balance |
string | yes | What entity_a holds of it: a receivable positive, a payable negative. |
b_balance |
string | yes | What entity_b holds of it, signed the same way. |
difference |
string | yes | a_balance + b_balance; zero when both agree. |
reason |
"amount_differs" | "cutoff" | "loan_movement_missing" | "mirror_draft" | "mirror_missing" | "mirror_pending_approval" | "mirror_rejected" | "payment_in_transit" | "unlinked_document" or null |
yes | loan_movement_missing (an entry of a movement is not posted yet on one side: explained) or amount_differs (unexplained); null when they agree. |
explained |
boolean | yes | True when the difference is a timing item (or zero). |
CarryingRow
| Field | Type | Required | Description |
|---|---|---|---|
entity |
string | yes | Entity code. |
functional_currency |
string | yes | The entity's functional currency. |
balance |
string | yes | What the books of the entity hold towards the partner on the group accounts at the day, in its functional currency: receivables positive, payables negative. For information; the revaluation moves it, the reconciliation does not. |
CurrencyRow
The open items of a pair in one document currency, in the document currency: neither functional currency, so a revaluation cannot disturb the comparison.
| Field | Type | Required | Description |
|---|---|---|---|
currency |
string | yes | Document currency. |
a_receivable |
string | yes | entity_a's receivable from entity_b: its open sales invoices to it, less its open credit notes. |
a_payable |
string | yes | entity_a's payable to entity_b: its open bills. |
b_receivable |
string | yes | entity_b's receivable from entity_a. |
b_payable |
string | yes | entity_b's payable to entity_a. |
a_net |
string | yes | a_receivable less a_payable. |
b_net |
string | yes | b_receivable less b_payable. |
difference |
string | yes | a_net plus b_net: zero when both sides agree exactly. |
DocumentRef
| Field | Type | Required | Description |
|---|---|---|---|
document_id |
string (uuid) | yes | Id of the document. |
entity |
string | yes | Code of the entity whose books hold it. |
number |
string or null | yes | Its number; null while it is a draft. |
kind |
string | yes | sales_invoice, sales_credit_note, purchase_bill ... |
status |
string | yes | draft, pending_approval, posted, rejected, void. |
document_date |
string (date) | yes | Its date. |
party_code |
string | yes | The customer or vendor, which is the other entity. |
total |
string | yes | Gross total in the document currency. |
EntryRef
| Field | Type | Required | Description |
|---|---|---|---|
entity |
string | yes | Entity code. |
entry_id |
string (uuid) | yes | The journal entry. |
number |
string or null | yes | Its number once posted. |
status |
string | yes | draft (a dividend the shareholder has not accepted yet), pending_approval, posted or rejected. |
GroupPartyOut
| Field | Type | Required | Description |
|---|---|---|---|
entity |
string | yes | Code of the entity whose books hold the party. |
kind |
"customer" | "vendor" |
yes | customer or vendor. |
code |
string | yes | The party's code, e.g. IC-DE01. |
party_id |
string (uuid) | yes | Id of the party. |
status |
string | yes | active: the relationship's approval activated it. |
InterestInput
| Field | Type | Required | Description |
|---|---|---|---|
through |
string (date) | yes | Accrue the interest up to and including this day, from the day after the last accrual (or from the first drawdown). |
ItemRow
One link, or one group document without a link, and what its two sides hold.
| Field | Type | Required | Description |
|---|---|---|---|
link_id |
string (uuid) or null | yes | The link; null for a document without one. |
origin |
DocumentRef |
yes | The origin document, or the unlinked document. |
counter |
DocumentRef or null |
yes | The counterpart, when there is one. |
currency |
string | yes | Document currency. |
origin_open |
string | yes | Open amount of the origin as of the day (posted). |
counter_open |
string | yes | Open amount of the counterpart; 0 until posted. |
difference |
string | yes | origin_open less counter_open (for an unlinked bill the minus of its open amount); zero when both sides agree. |
reason |
"amount_differs" | "cutoff" | "loan_movement_missing" | "mirror_draft" | "mirror_missing" | "mirror_pending_approval" | "mirror_rejected" | "payment_in_transit" | "unlinked_document" or null |
yes | Why they differ: a timing reason (mirror_missing, mirror_draft, mirror_pending_approval, payment_in_transit, cutoff) is explained and the counterpart's to resolve; mirror_rejected, unlinked_document and amount_differs are unexplained. Null when difference is zero. |
explained |
boolean | yes | True when the difference is wholly a timing reason (or zero). |
LinkOut
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | yes | Id of the link. |
relationship_id |
string (uuid) | yes | The relationship it belongs to. |
kind |
"credit_note" | "invoice" |
yes | invoice (a sales invoice and its purchase bill) or credit_note. |
status |
"accepted" | "drafted" | "mirror_rejected" | "pending" | "rejected" | "waiting" |
yes | pending (the counterpart could not be made: error says why; POST /v1/ic/links/{id}/retry), waiting (a credit note whose invoice's mirror is not posted), drafted (the counterpart is a draft a person accepts), accepted (posted), rejected (the receiver refused it; the sender corrects with a credit note) or mirror_rejected (a credit note of an invoice whose mirror was rejected: nothing to credit). |
currency |
string | yes | Document currency of both documents. |
net_total |
string | yes | The origin's net total: the counterpart must equal it to be posted. |
error |
string or null | yes | Why the counterpart could not be made, while pending. |
origin |
DocumentRef |
yes | The document that was posted. |
counter |
DocumentRef or null |
yes | The counterpart in the other entity; null while pending or waiting. |
origin_posted_by |
object | yes | Who posted the origin: this person does not accept the mirror. |
created_at |
string (date-time) | yes | When the origin was posted and linked (UTC). |
accepted_by |
object or null | yes | Who accepted (posted) the mirror. |
accepted_at |
string (date-time) or null | yes | When (UTC). |
rejected_by |
object or null | yes | Who rejected the mirror. |
rejected_at |
string (date-time) or null | yes | When (UTC). |
reject_reason |
string or null | yes | Why it was rejected. |
LoanInput
| Field | Type | Required | Description |
|---|---|---|---|
reference |
string | yes | The loan's reference, unique in the organization. (min length 1; max length 40) |
lender |
string | yes | Code (or id) of the entity that lends. |
borrower |
string | yes | Code (or id) of the entity that borrows. |
currency |
string or null | ISO 4217 currency of the loan. Omitted: the lender's functional currency. (min length 3; max length 3) | |
facility_amount |
decimal string | yes | The agreed amount: what may be drawn at most (a decimal string). (greater than 0) |
interest_rate_percent |
decimal string | yes | Fixed annual rate in percent, e.g. 3.0000. (min 0; max 100) |
interest_basis |
string | yes | The arm's-length basis the approvers accepted, in words (the benchmark, its source and date). Recorded, never judged. (min length 3; max length 2000) |
day_count |
"30/360" | "act/360" | "act/365" |
yes | act/360, act/365 (fixed) or 30/360 (European, 30E/360). |
start_date |
string (date) | yes | First day a drawdown may be dated. |
maturity_date |
string (date) | yes | The day the loan falls due; after the start. |
lender_bank_account |
string | yes | Code of the lender's bank account in its chart (an asset account): where drawdowns are paid from and repayments come in. |
borrower_bank_account |
string | yes | Code of the borrower's bank account in its chart (an asset account). |
net_investment |
boolean | IAS 21.15: settlement is neither planned nor likely, so the loan is part of the net investment in a foreign operation and the consolidation takes its exchange differences to the translation reserve (IAS 21.32). (default false) |
LoanOut
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | yes | Id of the loan. |
reference |
string | yes | The loan's reference. |
relationship_id |
string (uuid) | yes | The relationship of the two entities. |
lender |
string | yes | Code of the lending entity. |
borrower |
string | yes | Code of the borrowing entity. |
currency |
string | yes | Currency of the loan. |
facility_amount |
string | yes | What may be drawn at most. |
interest_rate_percent |
string | yes | Fixed annual rate in percent. |
interest_basis |
string | yes | The arm's-length basis the approvers accepted. |
day_count |
"30/360" | "act/360" | "act/365" |
yes | The day count of the interest. |
start_date |
string (date) | yes | First day a drawdown may be dated. |
maturity_date |
string (date) | yes | The day it falls due. |
lender_bank_account |
string | yes | The lender's bank account code. |
lender_bank_balance |
string | yes | The book balance of the lender's bank account (its posted entries) in the currency it holds (lender_bank_currency): where that is the loan's, a drawdown above it takes the account below zero in the books. |
lender_bank_currency |
string | The currency the lender's bank account holds (its own, or the lender's functional currency). (default "") |
|
borrower_bank_account |
string | yes | The borrower's bank account code. |
net_investment |
boolean | yes | Part of the net investment (IAS 21.15). |
status |
"active" | "closed" | "draft" |
yes | draft (waits for a second person), active or closed (repaid in full). |
principal |
string | yes | Principal outstanding: the drawdowns less the repayments recorded. |
accrued_through |
string (date) or null | yes | The last day interest has been accrued for; null before the first accrual. |
interest_open |
string | yes | Interest accrued and not settled yet, in the loan's currency. |
requested_by |
object | yes | Who asked for it, as an actor object. |
approved_by |
object or null | yes | Who approved it; null while draft. |
approved_at |
string (date-time) or null | yes | When it was approved (UTC). |
approval_id |
string (uuid) or null | yes | The approval request that waits (POST /v1/approvals/{id}/approve). |
closed_at |
string (date-time) or null | yes | When it was repaid in full (UTC). |
created_at |
string (date-time) | yes | When it was requested (UTC). |
MovementInput
| Field | Type | Required | Description |
|---|---|---|---|
value_date |
string (date) | yes | The day the money moves; both entries are dated it. |
amount |
decimal string | yes | In the loan's currency (a decimal string). (greater than 0) |
reference |
string or null | Your reference, e.g. the bank's; optional. (max length 200) |
MovementOut
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | yes | Id of the movement. |
kind |
"dividend_declared" | "interest_accrual" | "loan_drawdown" | "loan_repayment" | "settlement" |
yes | What moved. |
relationship_id |
string (uuid) | yes | The relationship of the two entities. |
loan_id |
string (uuid) or null | yes | The loan; null for a dividend. |
loan_reference |
string or null | yes | The loan's reference. |
value_date |
string (date) | yes | The day of the movement. |
amount |
string | yes | In currency. |
currency |
string | yes | Currency of the movement. |
reference |
string | yes | Reference. |
creditor |
EntryRef |
yes | The lender's entry (the shareholder's for a dividend). |
debtor |
EntryRef |
yes | The borrower's entry (the declaring entity's for a dividend). |
settles_id |
string (uuid) or null | yes | What a settlement settles. |
detail |
object | yes | For interest: from, through and the segments (principal and days); for a repayment or settlement the realised exchange differences. |
created_by |
object | yes | Who recorded it, as an actor object. |
created_at |
string (date-time) | yes | When (UTC). |
warnings |
array of string | What to know that did not stop it, when it was recorded, in English: that it takes the paying bank account below zero in the books on the value date (the lender's for a drawdown, the borrower's for a repayment or a settlement). | |
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. |
Reconciliation
| Field | Type | Required | Description |
|---|---|---|---|
as_of |
string (date) | yes | The day the open items are read as of. |
relationships |
array of RelationshipReconciliation |
yes | One entry per relationship. |
RejectInput
| Field | Type | Required | Description |
|---|---|---|---|
reason |
string | yes | Why the receiving entity refuses the document; the sender sees it. (min length 3; max length 1000) |
RelationshipInput
| Field | Type | Required | Description |
|---|---|---|---|
mirror_mode |
"draft" | "post" |
draft (default): the document made in the counterpart is a draft that a person there accepts. post: the system posts it at once under the system policy, a standing flow the approval authorises (a monthly management fee); never the default. (default "draft") |
|
tolerance_amount |
decimal string | The difference the reconciliation counts as agreed: rounding only, in tolerance_currency. Default 1.00. (min 0; default "1") |
|
tolerance_currency |
string or null | ISO 4217 currency of the tolerance. Default: the functional currency of entity_a as named in the request. (pattern ^[A-Z]{3}$) |
|
vat_group |
"ch_vat_group" | "de_organschaft" | "none" |
none (default), ch_vat_group (a Swiss VAT group, Art. 13 MWSTG: two Swiss entities) or de_organschaft (a German tax group, § 2 para. 2 no. 2 UStG: two German entities). From vat_group_from the supplies between the two are outside the scope of VAT (vat_scope outside, reason vat_group or organschaft) and no VAT report or return has them. Never between a Swiss and a German entity. (default "none") |
|
vat_group_from |
string (date) or null | The date from which the VAT group applies (a Swiss group starts at the beginning of a tax period, Art. 13 para. 2 MWSTG); required with a VAT group, refused without one. Documents dated before it carry VAT as usual. | |
vat_group_reference |
string or null | The registration or documentation of the group (a notice of the tax authority, the Organträger's confirmation); required with a VAT group. (max length 500) | |
pricing_method |
"cost_plus" | "cup" | "other" | "profit_split" | "resale_price" | "tnmm" |
yes | The transfer-pricing method the approvers accepted: cup (comparable uncontrolled price), resale_price, cost_plus, tnmm (transactional net margin), profit_split or other. The system records it and never judges a price. |
markup_percent |
decimal string or null | The mark-up in percent where the method has one; required for cost_plus. (min 0; max 1000) |
|
pricing_basis |
string | yes | The basis in words: the benchmark or study and its date. Mandatory: an approval without it is refused (§ 1 para. 1 AStG, OECD Model Convention Art. 9). (min length 3; max length 2000) |
pricing_documented_on |
string (date) | yes | The date the documentation of the prices was made (§ 90 para. 3 AO). |
entity_a |
string | yes | Code (or id) of one entity of the pair, e.g. CH01. |
entity_b |
string | yes | Code (or id) of the other entity, e.g. DE01. |
RelationshipOut
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | yes | Id of the relationship. |
entity_a |
string | yes | Code of the entity whose id sorts first. |
entity_b |
string | yes | Code of the other entity. |
entity_a_name |
string | yes | Name of entity_a. |
entity_b_name |
string | yes | Name of entity_b. |
status |
"active" | "pending" | "suspended" |
yes | pending (waits for a second person's approval), active or suspended. |
mirror_mode |
"draft" | "post" |
yes | draft or post. |
tolerance_amount |
string | yes | Difference counted as agreed. |
tolerance_currency |
string | yes | Currency of the tolerance. |
vat_group |
"ch_vat_group" | "de_organschaft" | "none" |
yes | none, ch_vat_group or de_organschaft. |
vat_group_from |
string (date) or null | yes | From when the VAT group applies. |
vat_group_reference |
string or null | yes | Registration or documentation. |
pricing_method |
"cost_plus" | "cup" | "other" | "profit_split" | "resale_price" | "tnmm" |
yes | The transfer-pricing method. |
markup_percent |
string or null | yes | The mark-up, where the method has one. |
pricing_basis |
string | yes | The basis the approvers accepted. |
pricing_documented_on |
string (date) | yes | Date of the documentation. |
terms_digest |
string | yes | SHA-256 of the pair and the terms the approval authorised. |
requested_by |
object | yes | Who asked for the terms in force. |
approved_by |
object or null | yes | Who approved them; null while pending. |
approved_at |
string (date-time) or null | yes | When (UTC). |
suspended_by |
object or null | yes | Who suspended it, if suspended. |
suspended_at |
string (date-time) or null | yes | When it was suspended (UTC). |
suspend_reason |
string or null | yes | Why it was suspended. |
created_at |
string (date-time) | yes | When the relationship was requested (UTC). |
approval_id |
string (uuid) or null | yes | The approval request waiting for a second person (the first approval, a change of terms or a resumption): POST /v1/approvals/{approval_id}/approve, not by the person who asked. Null when nothing waits. |
pending_terms |
object or null | yes | The terms a waiting change would put in force; null when none waits or the request is the first approval. |
parties |
array of GroupPartyOut |
yes | The four customer and vendor records the approval created, two in each entity; empty until approved. |
open_mirrors |
integer | yes | Mirror documents of this relationship waiting as drafts to be accepted; GET /v1/ic/links?relationship={id}&status=drafted lists them. |
not_made |
integer | yes | Links whose counterpart could not be made yet (pending; their error says why): GET /v1/ic/links?relationship={id}&status=pending lists them. |
rejected_mirrors |
integer | yes | Links whose mirror the receiving entity rejected: GET /v1/ic/links?relationship={id}&status=rejected lists them. |
RelationshipReconciliation
| Field | Type | Required | Description |
|---|---|---|---|
relationship_id |
string (uuid) | yes | The relationship. |
entity_a |
string | yes | Code of the first entity. |
entity_b |
string | yes | Code of the second entity. |
status |
"fail" | "n/a" | "pass" | "warn" |
yes | pass (the items add up to the tolerance or less), warn (what differs is entirely listed timing items), fail (a part is unexplained) or n/a (the relationship is not active). |
tolerance_amount |
string | yes | The tolerance of the relationship. |
tolerance_currency |
string | yes | Its currency. |
difference_in_tolerance_currency |
string or null | yes | The sum of the differences of all items, each converted at the ECB closing rate of the day, in tolerance_currency (absolute values); null when a rate is missing. The tolerance is applied to this figure. |
unexplained_in_tolerance_currency |
string or null | yes | The same for the unexplained items only. |
currencies |
array of CurrencyRow |
yes | The open items per document currency. |
items |
array of ItemRow |
yes | Every link with something open on either side and every group document nobody linked, each with its reason (null where the two sides agree); a link settled in full on both sides is left out. The differences of the items add up to difference of the currency rows. |
balances |
array of BalanceRow |
The loans, their accrued interest and the declared group dividends between the two, each with what both sides hold of it in its currency; their differences count with the items' towards the tolerance. | |
carrying |
array of CarryingRow |
yes | The carrying amounts of the two entities in their functional currencies. |
detail |
string | yes | The result in words. |
RelationshipUpdate
A change to a relationship: new terms (a new approval request), a suspension or the re-activation of a suspended relationship (a request), or a refresh of the group parties.
| Field | Type | Required | Description |
|---|---|---|---|
status |
"active" | "suspended" or null |
suspended stops new intercompany postings at once (one person, with a reason); open items stay and settle normally. active on a suspended relationship asks a second person to approve resuming. |
|
mirror_mode |
"draft" | "post" or null |
New mirror mode. | |
tolerance_amount |
decimal string or null | New tolerance. (min 0) | |
tolerance_currency |
string or null | New tolerance currency. (pattern ^[A-Z]{3}$) |
|
vat_group |
"ch_vat_group" | "de_organschaft" | "none" or null |
New VAT group. | |
vat_group_from |
string (date) or null | New VAT group start date. | |
vat_group_reference |
string or null | New VAT group reference. (max length 500) | |
pricing_method |
"cost_plus" | "cup" | "other" | "profit_split" | "resale_price" | "tnmm" or null |
New method. | |
markup_percent |
decimal string or null | New mark-up. (min 0; max 1000) | |
pricing_basis |
string or null | New pricing basis. (min length 3; max length 2000) | |
pricing_documented_on |
string (date) or null | New date of the documentation. | |
refresh_parties |
boolean | Read the name, address, VAT number, country and bank accounts of the two entities again into their four customer and vendor records, which are not edited by hand. Alone: it changes no terms. (default false) |
|
reason |
string or null | Why: required to suspend, kept with a change of terms in the audit trail. (min length 3; max length 1000) |
SettlementInput
| Field | Type | Required | Description |
|---|---|---|---|
loan |
string (uuid) or null | Settle the loan's accrued interest; or name a dividend. |
|
dividend |
string (uuid) or null | Settle a declared group dividend: the id of its dividend_declared movement. |
|
value_date |
string (date) | yes | The day of the payment. |
amount |
decimal string | yes | In the currency of what is settled; at most what is open. (greater than 0) |
payer_bank_account |
string or null | The paying entity's bank account code; default the loan's (for a dividend the account with the role bank). |
|
payee_bank_account |
string or null | The receiving entity's bank account code; default as above. | |
reference |
string or null | Your reference. (max length 200) |