Home Integration API reference
REST API for integrations and external apps
Payment accounts
Payment account endpoints cover account catalog management, account ledgers, account-focused reports, deposits, and fund transfers. Unless a section says otherwise, all endpoints require account.access, and non-admin users with restricted locations only see accounts that are enabled on their permitted business locations.
Lists payment accounts visible to the token user with the same location-based visibility rules as the web Payment Accounts list.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/accounts |
| Permission | account.access. |
| Visibility | When the token user is not a business admin and has restricted locations, only accounts enabled as default payment accounts on permitted locations are returned. |
| Search behavior | q requires at least 2 characters when sent. Legacy search still matches account name or account number. |
| CSV behavior | format=csv downloads all matching rows as UTF-8 CSV with BOM and ignores page and per_page. Nested objects are JSON-encoded in CSV cells. |
| Success response | 200 with paginated PaymentAccountListItem rows or a CSV download. |
| Parameter | Type | Required | Description |
|---|---|---|---|
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
is_closed | boolean-like string | No | 0 or 1 to filter open versus closed accounts. |
q, search | string | No | Text search across account name and account number. |
format | string | No | json (default) or csv. |
AccountTypeSummary object| Field | Type | Description |
|---|---|---|
id | integer | Account-type id. |
name | string | Account-type label. |
parent | object | null | Optional parent account type with id and name. |
AccountDetailEntry object| Field | Type | Description |
|---|---|---|
label | string | Display label for one custom account detail row. |
value | string | Saved value for that detail row. |
PaymentAccountListItem object| Field | Type | Description |
|---|---|---|
id, name, account_number | mixed | Account identity fields. |
note | string | null | Optional free-text note stored on the account. |
is_closed | boolean | Whether the account has been marked closed. |
balance | number | Running balance computed as credits minus debits from account transactions. |
account_type | AccountTypeSummary | null | Resolved type hierarchy for the account. |
account_details | array<AccountDetailEntry> | null | Optional structured detail rows configured on the account. |
| Field | Type | Description |
|---|---|---|
data | array<PaymentAccountListItem> | The current result page. |
meta.current_page, meta.last_page, meta.per_page, meta.total | integer | Laravel paginator metadata. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The payment accounts were returned successfully. | { "data": [...], "meta": { ... } } or CSV download. |
403 | The token user lacks account.access. | { "message": "Unauthorized" } |
422 | The query string failed validation or q was shorter than 2 characters. | Laravel validation JSON or { "message": string }. |
Returns one visible payment account with its running balance, type hierarchy, and creator id.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/accounts/{id} |
| Permission | account.access. |
| Visibility | Uses the same permitted-location account visibility as List payment accounts. |
| CSV behavior | format=csv streams one UTF-8 BOM row whose data_json cell matches the JSON data object. |
| Success response | 200 with one PaymentAccountDetail object. |
| Parameter | Type | Required | Description |
|---|---|---|---|
format | string | No | json (default) or csv. CSV download name: payment-account-{id}-{business_id}-{timestamp}.csv. |
PaymentAccountDetail object| Field | Type | Description |
|---|---|---|
| All PaymentAccountListItem fields | mixed | The same fields returned by the list endpoint. |
created_by | integer | null | The user id that created the account. |
| Field | Type | Description |
|---|---|---|
data | PaymentAccountDetail | The requested payment-account payload. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The payment account was returned successfully. | { "data": { ... } } or CSV download. |
403 | The token user lacks account.access. | { "message": "Unauthorized" } |
404 | The payment account id does not exist or is not visible to the token user. | { "message": "Not found" } |
Returns the paginated account ledger for one visible payment account, including optional opening-balance math for date-range queries.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/accounts/{id}/transactions |
| Permission | account.access. |
| Visibility | Uses the same account visibility as Get payment account. |
| Date rule | start_date and end_date must be sent together. When present, data.beginning_balance is the net balance before start_date. |
| CSV behavior | format=csv downloads all matching lines and can prepend one opening_balance row when a date range is applied. |
| Success response | 200 with one ledger payload plus pagination metadata. |
| Parameter | Type | Required | Description |
|---|---|---|---|
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
start_date, end_date | string | Conditional | Date strings normalized through Util::uf_date(). Both must be sent together. |
type | string | No | credit or debit. |
q | string | No | Matches note, sub type, payment reference number, or a numeric ledger-line id. Requires at least 2 characters when sent. |
format | string | No | json (default) or csv. |
AccountTransactionLine object| Field | Type | Description |
|---|---|---|
id, account_id | integer | Ledger-line id and owning account id. |
type, sub_type | string | null | Credit/debit identity plus transaction subtype such as deposit or fund_transfer. |
amount | number | Stored transaction amount. |
operation_date | string | null | ISO-8601 operation timestamp. |
note | string | null | Optional note stored on the account transaction. |
transaction_id, transaction_payment_id, transfer_transaction_id | integer | null | Optional linked transaction, payment, and paired transfer ids. |
payment_ref_no, payment_method | string | null | Resolved payment metadata when the account transaction is linked to a transaction payment. |
| Field | Type | Description |
|---|---|---|
data.account_id | integer | The requested payment-account id. |
data.beginning_balance | number | null | Net balance before start_date when a date range is applied, otherwise null. |
data.lines | array<AccountTransactionLine> | The current result page of ledger lines. |
meta.current_page, meta.last_page, meta.per_page, meta.total, meta.start_date, meta.end_date, meta.type, meta.q | mixed | Pagination metadata plus echoed filters. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The account ledger was returned successfully. | { "data": { ... }, "meta": { ... } } or CSV download. |
403 | The token user lacks account.access. | { "message": "Unauthorized" } |
404 | The payment account id does not exist or is not visible to the token user. | { "message": "Not found" } |
422 | The date pair is incomplete or reversed, the query string failed validation, or q was shorter than 2 characters. | Laravel validation JSON or { "message": string }. |
Creates a payment account for the token user's business and can optionally seed its opening balance in the same request.
| Property | Value |
|---|---|
| Method | POST |
| Path | /api/v1/integration/accounts |
| Permission | account.access. |
| Write guard | Returns 403 in demo environments. |
| Type rule | account_type_id, when sent, must belong to the current business. |
| Opening-balance rule | When opening_balance is non-zero, the API creates one opening_balance account-transaction row. Positive values create a credit; negative values create a debit. |
| Success response | 201 with one PaymentAccountDetail object. |
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Display name for the payment account. |
account_number | string | Yes | Business-visible account number or code. |
account_type_id | integer | null | No | Optional account-type id that must belong to the current business. |
note | string | null | No | Optional free-text note up to 2000 characters. |
account_details | array<AccountDetailEntry> | null | No | Optional structured detail rows. Empty rows are discarded by the API. |
opening_balance | number | null | No | Optional opening balance parsed with the business currency settings. |
| Field | Type | Description |
|---|---|---|
data | PaymentAccountDetail | The created payment-account payload reloaded with its running balance. |
| Status | When it happens | Response shape |
|---|---|---|
201 | The payment account was created successfully. | { "data": { ... } } |
403 | Demo mode is active or the token user lacks account.access. | { "message": string } |
422 | The request body failed validation, account_type_id does not belong to the business, or the business currency is not configured. | Laravel validation JSON or { "message": string }. |
500 | The account row could not be created. | { "message": "Could not create account" } |
Updates the metadata for one visible payment account without changing its transaction history.
| Property | Value |
|---|---|
| Method | PATCH or PUT |
| Path | /api/v1/integration/accounts/{id} |
| Permission | account.access. |
| Visibility | Uses the same account visibility rules as Get payment account. |
| Write guard | Returns 403 in demo environments. |
| Empty-update rule | The request must include at least one valid updatable field; otherwise the API returns 422. |
| Success response | 200 with the refreshed PaymentAccountDetail object. |
| Field | Type | Required | Description |
|---|---|---|---|
name, account_number | string | No | Optional basic identity fields. |
account_type_id | integer | null | No | Optional account-type change. Non-null values must belong to the current business. |
note | string | null | No | Optional note update. |
account_details | array<AccountDetailEntry> | null | No | Optional replacement for the structured detail rows. |
| Field | Type | Description |
|---|---|---|
data | PaymentAccountDetail | The updated payment-account payload reloaded with its running balance. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The payment account was updated successfully. | { "data": { ... } } |
403 | Demo mode is active or the token user lacks account.access. | { "message": string } |
404 | The payment account id does not exist or is not visible to the token user. | { "message": "Not found" } |
422 | The request body failed validation, no valid fields were supplied, or account_type_id does not belong to the business. | Laravel validation JSON or { "message": string }. |
500 | The account row could not be updated. | { "message": "Could not update account" } |
Marks a visible payment account as closed, matching the web Close action.
| Property | Value |
|---|---|
| Method | POST |
| Path | /api/v1/integration/accounts/{id}/close |
| Permission | account.access. |
| Visibility | Uses the same account visibility rules as Get payment account. |
| Write guard | Returns 403 in demo environments. |
| Business rule | Returns 422 when the account is already closed. |
| Success response | 200 with the refreshed PaymentAccountDetail object. |
| Field | Type | Description |
|---|---|---|
data | PaymentAccountDetail | The closed payment-account payload with is_closed = true. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The payment account was closed successfully. | { "data": { ... } } |
403 | Demo mode is active or the token user lacks account.access. | { "message": string } |
404 | The payment account id does not exist or is not visible to the token user. | { "message": "Not found" } |
422 | The account is already closed. | { "message": string } |
500 | The account row could not be closed. | { "message": "Could not close account" } |
Returns balance-sheet figures derived from purchase totals, sell totals, account balances, and closing stock.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/accounts/reports/balance-sheet |
| Permission | account.access. |
| Date default | When end_date is omitted, the API resolves it to today. |
| Location rule | When location_id is provided, it must exist for the business and be within the token user's permitted locations. |
| CSV behavior | format=csv flattens the summary into section / field / value rows. |
| Parameter | Type | Required | Description |
|---|---|---|---|
end_date | string | No | Business-format date resolved through TransactionUtil::uf_date(). Defaults to today. |
location_id | integer | No | Optional business-location filter. |
format | string | No | json (default) or csv. |
| Field | Type | Description |
|---|---|---|
data.end_date | string | The resolved end date used for the report. |
data.supplier_due, data.customer_due, data.closing_stock | number | Headline balance-sheet summary figures. |
data.account_balances | object | Map of account name to balance through the resolved end_date. |
data.capital_account_details | null | Currently always null. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The balance sheet was returned successfully. | { "data": { ... } } or CSV download. |
403 | The token user lacks account.access or is forbidden from the requested location. | { "message": string } |
404 | The requested location id does not exist for the current business. | { "message": "Location not found" } |
422 | The query string failed validation. | Laravel validation JSON. |
Returns supplier due, customer due, and account balances through one resolved end date.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/accounts/reports/trial-balance |
| Permission | account.access. |
| Date default | When end_date is omitted, the API resolves it to today. |
| Location rule | When location_id is provided, it must exist for the business and be within the token user's permitted locations. |
| CSV behavior | format=csv flattens the summary into section / field / value rows. |
| Parameter | Type | Required | Description |
|---|---|---|---|
end_date | string | No | Business-format date resolved through TransactionUtil::uf_date(). Defaults to today. |
location_id | integer | No | Optional business-location filter. |
format | string | No | json (default) or csv. |
| Field | Type | Description |
|---|---|---|
data.end_date | string | The resolved end date used for the report. |
data.supplier_due, data.customer_due | number | Headline trial-balance summary figures. |
data.account_balances | object | Map of account name to balance through the resolved end_date. |
data.capital_account_details | null | Currently always null. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The trial balance was returned successfully. | { "data": { ... } } or CSV download. |
403 | The token user lacks account.access or is forbidden from the requested location. | { "message": string } |
404 | The requested location id does not exist for the current business. | { "message": "Location not found" } |
422 | The query string failed validation. | Laravel validation JSON. |
Returns cash-flow rows built from account transactions, transaction payments, contacts, and running balance calculations.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/accounts/reports/cash-flow |
| Permission | account.access. |
| Ordering | Rows are sorted ascending by operation_date and then by ledger-line id. |
| Date filter | The date range is only applied when both start_date and end_date are supplied. Sending only one date passes validation but leaves the result unfiltered. |
| Location rule | When location_id is provided, it must exist for the business and be within the token user's permitted locations. |
| CSV behavior | format=csv downloads all matching rows and ignores pagination. |
| Parameter | Type | Required | Description |
|---|---|---|---|
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
start_date, end_date | string | No | Date strings resolved through TransactionUtil::uf_date(). The filter only applies when both are supplied. |
type | string | No | credit or debit. |
location_id, account_id | integer | No | Optional location and account filters. |
only_payment_recovered | boolean | No | Applies the same special recovered-payment filter used by the web Cash Flow screen. |
q | string | No | Matches account name, payment ref, transaction number, contact fields, created-by name, linked transaction invoice/ref, or numeric account-transaction and account ids. Requires at least 2 characters when sent. |
format | string | No | json (default) or csv. |
CashFlowReportRow object| Field | Type | Description |
|---|---|---|
id, account_id, account_name | mixed | Ledger-line and account identity fields. |
type, sub_type | string | null | Credit/debit identity and transaction subtype. |
amount, debit, credit | number | null | Raw amount plus debit/credit convenience columns. |
operation_date | string | null | ISO-8601 operation timestamp. |
method, method_label, payment_ref_no, transaction_no | string | null | Resolved payment-method metadata. |
is_return, is_advance | integer | Return and advance-payment flags. |
payment_for_contact, payment_for_type, payment_for_business_name, added_by | string | null | Contact and creator display fields. |
total_recovered, child_invoice_numbers | number | string | null | Recovered total and comma-separated child invoice numbers. |
account_balance_after, combined_balance_after | number | Running balances after the current line. |
| Field | Type | Description |
|---|---|---|
data | array<CashFlowReportRow> | The current result page of cash-flow rows. |
meta.current_page, meta.last_page, meta.per_page, meta.total, meta.q | mixed | Pagination metadata plus the resolved text filter. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The cash-flow report was returned successfully. | { "data": [...], "meta": { ... } } or CSV download. |
403 | The token user lacks account.access or is forbidden from the requested location. | { "message": string } |
404 | The requested location id does not exist for the current business. | { "message": "Location not found" } |
422 | The query string failed validation or q was shorter than 2 characters. | Laravel validation JSON or { "message": string }. |
Returns payment lines linked to transactions, aligned with the web Payment Account Report grid.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/accounts/reports/payment-account-report |
| Permission | account.access. |
| Row scope | Only parent payment rows are included. Advance payments are excluded. Users with restricted locations only see payments from transactions in permitted locations. |
| Account filter | account_id accepts a numeric account id or the literal string none to filter unlinked payments. |
| CSV behavior | format=csv downloads all matching rows and ignores pagination. |
| Parameter | Type | Required | Description |
|---|---|---|---|
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
start_date, end_date | string | Conditional | Date strings resolved through TransactionUtil::uf_date(). Both must be sent together. |
account_id | integer | string | No | Numeric account id or none for payments with no linked account. |
q, search | string | No | Matches account name/number, invoice, transaction ref, payment ref, contact fields, or numeric payment/transaction ids. Requires at least 2 characters when sent. |
format | string | No | json (default) or csv. |
PaymentAccountReportRow object| Field | Type | Description |
|---|---|---|
id, paid_on, amount, payment_ref_no | mixed | Payment identity and timing fields. |
method, method_label | string | null | Payment method key and resolved label. |
is_advance, is_return | integer | Advance-payment and return flags. |
transaction | object | Linked transaction summary with id, type, ref_no, invoice_no, and location_id. |
account | object | null | Linked account summary with id, name, and account_number. |
contact | object | null | Optional contact summary with name and type. |
| Field | Type | Description |
|---|---|---|
data | array<PaymentAccountReportRow> | The current result page. |
meta.current_page, meta.last_page, meta.per_page, meta.total, meta.q | mixed | Pagination metadata plus the resolved text filter. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The payment-account report was returned successfully. | { "data": [...], "meta": { ... } } or CSV download. |
403 | The token user lacks account.access. | { "message": "Unauthorized" } |
422 | The date pair is incomplete, account_id is invalid, the query string failed validation, or q was shorter than 2 characters. | Laravel validation JSON or { "message": string }. |
Records a deposit into one payment account and can optionally create the paired debit from another account in the same transaction.
| Property | Value |
|---|---|
| Method | POST |
| Path | /api/v1/integration/accounts/deposit |
| Permission | account.access. |
| Write guard | Returns 403 in demo environments. |
| Account rule | account_id must point to a visible, open account. If from_account_id is sent, it must also be visible, open, and different from account_id. |
| Amount rule | amount is parsed through the business currency configuration and must be greater than zero. |
| Success response | 201 with the created credit line and the optional paired debit line. |
| Field | Type | Required | Description |
|---|---|---|---|
account_id | integer | Yes | The account that will receive the credit deposit line. |
amount | number | Yes | Deposit amount. Must be greater than zero after currency parsing. |
operation_date | string | Yes | Parseable date or datetime string used for the account-transaction timestamp. |
from_account_id | integer | null | No | Optional source account for the paired debit line. Must differ from account_id. |
note | string | null | No | Optional note up to 1000 characters. |
| Field | Type | Description |
|---|---|---|
data.credit | AccountTransactionLine | The created credit-side deposit transaction. |
data.debit | AccountTransactionLine | null | The optional paired debit transaction when from_account_id was supplied. |
| Status | When it happens | Response shape |
|---|---|---|
201 | The deposit was recorded successfully. | { "data": { "credit": { ... }, "debit": { ... } | null } } |
403 | Demo mode is active or the token user lacks account.access. | { "message": string } |
404 | account_id or from_account_id does not exist or is not visible to the token user. | { "message": "Account not found" } |
422 | The request body failed validation, the source and destination accounts are the same, the amount is invalid, an account is closed, or the business currency is not configured. | Laravel validation JSON or { "message": string }. |
500 | The deposit transaction could not be recorded. | { "message": "Could not record deposit" } |
Transfers funds between two visible, open payment accounts by creating one debit and one credit account-transaction row.
| Property | Value |
|---|---|
| Method | POST |
| Path | /api/v1/integration/accounts/fund-transfer |
| Permission | account.access. |
| Write guard | Returns 403 in demo environments. |
| Account rule | from_account_id and to_account_id must point to visible, open accounts and must differ from each other. |
| Amount rule | amount is parsed through the business currency configuration and must be greater than zero. |
| Success response | 201 with the created debit and credit transfer lines. |
| Field | Type | Required | Description |
|---|---|---|---|
from_account_id | integer | Yes | The account that will receive the debit transfer line. |
to_account_id | integer | Yes | The account that will receive the credit transfer line. |
amount | number | Yes | Transfer amount. Must be greater than zero after currency parsing. |
operation_date | string | Yes | Parseable date or datetime string used for the account-transaction timestamp. |
note | string | null | No | Optional note up to 1000 characters. |
| Field | Type | Description |
|---|---|---|
data.debit | AccountTransactionLine | The created debit-side transfer transaction. |
data.credit | AccountTransactionLine | The created credit-side transfer transaction. |
| Status | When it happens | Response shape |
|---|---|---|
201 | The fund transfer was recorded successfully. | { "data": { "debit": { ... }, "credit": { ... } } } |
403 | Demo mode is active or the token user lacks account.access. | { "message": string } |
404 | from_account_id or to_account_id does not exist or is not visible to the token user. | { "message": "Account not found" } |
422 | The request body failed validation, the source and destination accounts are the same, the amount is invalid, an account is closed, or the business currency is not configured. | Laravel validation JSON or { "message": string }. |
500 | The fund transfer could not be recorded. | { "message": "Could not record transfer" } |