REST API reference
420 operations, generated from the product's OpenAPI description. All paths are on the product host, for example https://nrerp.khanwco.net/api/accounts. See Authentication for tokens and errors.
accounts
GET /api/accounts
The chart of accounts.
POST /api/accounts
Add accounts to the chart (owner, CFO or accountant).
| Field | Where | Required | Notes |
|---|---|---|---|
accounts | body (array) | yes | Parents before their children. |
GET /api/accounts/{code}/ledger
One account's posted lines between two dates with opening balance, running balance and closing balance (base currency, debit positive); a heading account includes the accounts under it.
| Field | Where | Required | Notes |
|---|---|---|---|
code | path | yes | |
from | query | First date (default: from the beginning) | |
to | query | Last date (default: through the last posting) | |
branch | query | ||
project | query | ||
cost_centre | query | ||
page | query | ||
page_size | query |
apikeys
GET /api/api-keys
Your API keys (owners and CFOs also see the company's keys).
POST /api/api-keys
Make an API key.
| Field | Where | Required | Notes |
|---|---|---|---|
name | body (string) | yes | |
kind | body (string) | ||
scopes | body (array) | yes | read, write, read:<area>, write:<area>, mcp |
expires_in_days | body (integer) | ||
rate_per_minute | body (integer) |
GET /api/api-keys/scopes
The scopes a key can have and the areas that read:/write: can name.
POST /api/api-keys/{key_id}/revoke
Revoke a key now (yours, or as owner / CFO any company key).
| Field | Where | Required | Notes |
|---|---|---|---|
key_id | path | yes |
POST /api/api-keys/{key_id}/rotate
A new secret for your key (same name, scopes and limit); the old secret stops working now.
| Field | Where | Required | Notes |
|---|---|---|---|
key_id | path | yes |
audit
GET /api/audit/verify-chain
Recompute the tamper-evident hash chain of every posted entry; reports the first entry that was altered.
auth
POST /api/auth/accept-invite
Set your password from the one-time invite link an owner/CFO gave you, and sign in.
| Field | Where | Required | Notes |
|---|---|---|---|
token | body (string) | yes | |
password | body (string) | yes |
POST /api/auth/continue
The one form: email + password.
| Field | Where | Required | Notes |
|---|---|---|---|
email | body (string) | yes | |
password | body (string) | yes | A new account needs at least 10 characters. |
full_name | body (string/null) | ||
base_currency | body (string) | ||
country | body (string) |
POST /api/auth/forgot
Forgot password: emails a one-time link (15 minutes, works once; a newer link ends older ones).
| Field | Where | Required | Notes |
|---|---|---|---|
email | body (string) | yes |
POST /api/auth/google
Continue with Google: send the ID token (credential) from Google's button.
| Field | Where | Required | Notes |
|---|---|---|---|
credential | body (string) | yes | The ID token from Google's sign-in button |
POST /api/auth/magic-link
Sign in by email instead of a password: emails a one-time sign-in link (15 minutes, works once).
| Field | Where | Required | Notes |
|---|---|---|---|
email | body (string) | yes |
POST /api/auth/magic-signin
Sign in with the token from an emailed sign-in link.
| Field | Where | Required | Notes |
|---|---|---|---|
token | body (string) | yes |
GET /api/auth/me
Who am I, and which companies (with my role in each) can I work in.
GET /api/auth/options
Which sign-in options are on (no sign-in needed): the public Google client id, or null when Google is off.
POST /api/auth/otp/request
Email me a code: ONE email with a 6-digit code (10 minutes, once, 5 tries) and a sign-in link.
| Field | Where | Required | Notes |
|---|---|---|---|
email | body (string) | yes |
POST /api/auth/otp/verify
Sign in with the email + the 6-digit code.
| Field | Where | Required | Notes |
|---|---|---|---|
email | body (string) | yes | |
code | body (string) | yes | The 6 digits from the sign-in email |
POST /api/auth/password
Change your password (needs the current one).
| Field | Where | Required | Notes |
|---|---|---|---|
current_password | body (string) | yes | |
new_password | body (string) | yes |
POST /api/auth/refresh
Spend the refresh token for a new pair.
| Field | Where | Required | Notes |
|---|---|---|---|
refresh_token | body (string) | yes |
POST /api/auth/reset
Choose a new password with the token from the emailed link.
| Field | Where | Required | Notes |
|---|---|---|---|
token | body (string) | yes | |
new_password | body (string) | yes |
POST /api/auth/signin
Email + password → a 15-minute access token and a rotating refresh token.
| Field | Where | Required | Notes |
|---|---|---|---|
email | body (string) | yes | |
password | body (string) | yes |
POST /api/auth/signout
End this sign-in; with all_devices, every sign-in and every access token of this user.
| Field | Where | Required | Notes |
|---|---|---|---|
refresh_token | body (string) | yes | |
all_devices | body (boolean) |
POST /api/auth/signup
Create a new company and its owner account, and sign in.
| Field | Where | Required | Notes |
|---|---|---|---|
company_name | body (string) | yes | |
full_name | body (string) | yes | |
email | body (string) | yes | |
password | body (string) | yes | At least 10 characters. |
base_currency | body (string) | ||
country | body (string) |
backup
GET /api/backup
List Backups
POST /api/backup
Start a complete backup of this company (books, parties, stock, documents, files, settings, people without passwords).
GET /api/backup/download/{job_id}
The archive, streamed.
| Field | Where | Required | Notes |
|---|---|---|---|
job_id | path | yes | |
c | query | yes | |
e | query | yes | |
s | query | yes |
GET /api/backup/history
Backup History
POST /api/backup/preview
Upload a backup (.zip, as the request body) and see what it holds and what would change in this company.
GET /api/backup/schedule
Get Backup Schedule
PUT /api/backup/schedule
Set Backup Schedule
| Field | Where | Required | Notes |
|---|---|---|---|
frequency | body (string) | yes | |
keep_copies | body (integer) |
GET /api/backup/{job_id}
Get Backup
| Field | Where | Required | Notes |
|---|---|---|---|
job_id | path | yes |
POST /api/backup/{job_id}/email-link
E-mail the download link to the signed-in admin's OWN address (never anyone else).
| Field | Where | Required | Notes |
|---|---|---|---|
job_id | path | yes |
POST /api/backup/{job_id}/link
Backup Link
| Field | Where | Required | Notes |
|---|---|---|---|
job_id | path | yes |
POST /api/backup/{job_id}/resume
Resume Backup
| Field | Where | Required | Notes |
|---|---|---|---|
job_id | path | yes |
bank
GET /api/bank-accounts
Every bank and cash account with its book balance (bank currency and base) as of a date (default today).
| Field | Where | Required | Notes |
|---|---|---|---|
as_of | query |
POST /api/bank-accounts
Link a postable asset account of the chart as a bank or cash account in one currency (owner, CFO or accountant).
| Field | Where | Required | Notes |
|---|---|---|---|
code | body (string) | yes | |
name | body (string) | yes | |
account | body (string) | yes | A postable asset account of the chart (not a control account) |
currency | body (string/null) | Default: the base currency | |
bank_name | body (string) | Chosen from /api/lookups/banks (or added there as 'other') | |
bank_country | body (string/null) | ||
swift | body (string) | ||
account_number | body (string) | ||
reconcile_from | body (string/null) | Reconciliation starts on this date | |
statement_opening_balance | body (number/string) | The bank's balance on reconcile_from |
GET /api/bank-accounts/{code}
One bank or cash account with its book balance as of a date (default today).
| Field | Where | Required | Notes |
|---|---|---|---|
code | path | yes | |
as_of | query |
POST /api/bank-accounts/{code}/auto-match
Match unmatched statement lines to posted ledger lines automatically — only clear, unique matches at or above min_confidence; the rest come back as suggestions for a person.
| Field | Where | Required | Notes |
|---|---|---|---|
code | path | yes | |
min_confidence | body (number) | ||
date_window | body (integer) | Days between the statement and the ledger line that still count |
GET /api/bank-accounts/{code}/lines
Statement lines of a bank account (oldest first); filter matched / unmatched and by date.
| Field | Where | Required | Notes |
|---|---|---|---|
code | path | yes | |
status | query | ||
start | query | ||
end | query |
POST /api/bank-accounts/{code}/statements
Import a bank statement file (CSV, OFX or MT940 text) into this bank account.
| Field | Where | Required | Notes |
|---|---|---|---|
code | path | yes | |
content | body (string) | yes | The statement file's text |
format | body (string) | ||
filename | body (string) | ||
columns | body (object/null) | CSV only: the file's column names when they are not the usual ones | |
date_format | body (string/null) | CSV only, e.g. |
GET /api/bank-lines/{line_id}
One statement line: date, amount (+ in / − out), text, whether it is matched and any draft made from it.
| Field | Where | Required | Notes |
|---|---|---|---|
line_id | path | yes |
POST /api/bank-lines/{line_id}/draft
Explain an unmatched statement line with a DRAFT: a journal entry (counter account, e.g.
| Field | Where | Required | Notes |
|---|---|---|---|
line_id | path | yes | |
branch | body (string/null) | Branch / project / cost-centre code (optional) | |
project | body (string/null) | Branch / project / cost-centre code (optional) | |
cost_centre | body (string/null) | Branch / project / cost-centre code (optional) | |
kind | body (string) | ||
account | body (string/null) | journal: the counter account code (bank charges, interest …) | |
party | body (string/null) | customer_receipt / vendor_payment: the customer or vendor code | |
allocations | body (array) | Receipts/payments: invoices or bills it settles | |
fx_rate | body (number/string/null) | ||
memo | body (string/null) |
POST /api/bank-lines/{line_id}/match
Tie a statement line to one or more posted ledger lines of the same bank account that add up to it exactly.
| Field | Where | Required | Notes |
|---|---|---|---|
line_id | path | yes | |
journal_line_ids | body (array) | yes | Posted ledger lines that add up to the statement line exactly |
GET /api/bank-lines/{line_id}/suggestions
Unmatched ledger lines that could be this statement line, best first, with their confidence (0..1).
| Field | Where | Required | Notes |
|---|---|---|---|
line_id | path | yes | |
date_window | query |
POST /api/bank-lines/{line_id}/unmatch
Undo the match of a statement line (recorded: who and when; the match stays in history).
| Field | Where | Required | Notes |
|---|---|---|---|
line_id | path | yes |
POST /api/bank-transfers
Money from one bank/cash account to another as DRAFT entries (same currency: one; between currencies: two through a transit account, the exchange difference on the base side).
| Field | Where | Required | Notes |
|---|---|---|---|
from_bank | body (string) | yes | |
to_bank | body (string) | yes | |
transfer_date | body (string) | yes | |
amount | body (number/string) | yes | Amount sent (from-bank currency) |
to_amount | body (number/string/null) | Amount received (other currency) | |
from_rate | body (number/string/null) | ||
to_rate | body (number/string/null) | ||
transit_account | body (string/null) | Between currencies: the money-in-transit account | |
memo | body (string) |
companies
GET /api/companies
The companies you belong to: your role, personal or commercial, the plan and whether it is active or expired (read-only).
POST /api/companies
Create another company with you as its owner (default approval matrix included).
| Field | Where | Required | Notes |
|---|---|---|---|
name | body (string) | yes | |
base_currency | body (string) | ||
country | body (string) | ||
kind | body (string) | personal: free for life, just you, one per person |
GET /api/subscription
This company's kind, plan, status (active / expired = read-only), trial end, features and how much of each is used.
company e-mail
DELETE /api/mail-setup
Forget the company address and its password.
GET /api/mail-setup
The company's own e-mail address and server, if connected.
POST /api/mail-setup/connect
Log in to the company's mail server with this password; when it works the password is saved encrypted.
| Field | Where | Required | Notes |
|---|---|---|---|
email | body (string) | yes | |
password | body (string) | yes | |
display_name | body (string) | ||
manual | body (object/null) |
POST /api/mail-setup/find
Find the mail server for an address, the way mail apps do (known providers, autoconfig, Autodiscover, DNS, MX, trials).
| Field | Where | Required | Notes |
|---|---|---|---|
email | body (string) | yes |
GET /api/mail-setup/history
Mail History
GET /api/mail-setup/oauth/{provider}
Hook for 'Sign in with Google / Microsoft' (OAuth2 XOAUTH2 for SMTP).
| Field | Where | Required | Notes |
|---|---|---|---|
provider | path | yes |
POST /api/mail-setup/test
Send ONE test message from the company address to YOUR OWN address.
| Field | Where | Required | Notes |
|---|---|---|---|
to | body (string) | yes |
crm
GET /api/crm/activities
Calls, meetings, e-mails, visits and WhatsApp notes logged by hand, newest first (filter by contact, customer, deal, lead or mine).
| Field | Where | Required | Notes |
|---|---|---|---|
contact_id | query | ||
party_id | query | ||
deal_id | query | ||
lead_id | query | ||
mine | query |
POST /api/crm/activities
Log a call / meeting / e-mail / visit / WhatsApp note with a contact, customer, deal or lead; optionally set the follow-up task.
| Field | Where | Required | Notes |
|---|---|---|---|
kind | body (string) | yes | |
subject | body (string) | yes | |
details | body (string) | ||
happened_at | body (string/null) | When it happened (default: now) | |
contact_id | body (string/null) | ||
party_id | body (string/null) | ||
deal_id | body (string/null) | ||
lead_id | body (string/null) | ||
follow_up | body (object/null) | The next step: becomes a task (To-Do) for its person |
GET /api/crm/contacts
Contacts (people at customers / vendors) you may see; search by name, job, phone, e-mail or company.
| Field | Where | Required | Notes |
|---|---|---|---|
q | query | ||
party_id | query | ||
include_closed | query |
POST /api/crm/contacts
Add a person at one or more customers / vendors.
| Field | Where | Required | Notes |
|---|---|---|---|
full_name | body (string) | yes | |
job_role | body (string) | Their job at the customer / vendor, e.g. | |
phones | body (array) | ||
emails | body (array) | ||
language | body (string) | Language they prefer, e.g. | |
whatsapp_opt_in | body (boolean) | They agreed to receive WhatsApp messages | |
party_ids | body (array) | Customers / vendors this person works for |
GET /api/crm/contacts/{contact_id}
One contact: their customers / vendors, notes timeline, activities and open tasks.
| Field | Where | Required | Notes |
|---|---|---|---|
contact_id | path | yes |
PUT /api/crm/contacts/{contact_id}
Change a contact's details, or close it (active=false).
| Field | Where | Required | Notes |
|---|---|---|---|
contact_id | path | yes | |
full_name | body (string) | yes | |
job_role | body (string) | Their job at the customer / vendor, e.g. | |
phones | body (array) | ||
emails | body (array) | ||
language | body (string) | Language they prefer, e.g. | |
whatsapp_opt_in | body (boolean) | They agreed to receive WhatsApp messages | |
active | body (boolean) | false closes the contact (kept, hidden from lists) |
POST /api/crm/contacts/{contact_id}/parties
Link a contact to another customer / vendor (or unlink=true).
| Field | Where | Required | Notes |
|---|---|---|---|
contact_id | path | yes | |
party_id | body (string) | yes | |
unlink | body (boolean) |
GET /api/crm/deals
Deals in the pipeline (default: open ones), in stage order.
| Field | Where | Required | Notes |
|---|---|---|---|
status | query | ||
owner_id | query | ||
party_id | query |
POST /api/crm/deals
Open a deal with a customer or a lead, with its expected value in the company's currency.
| Field | Where | Required | Notes |
|---|---|---|---|
title | body (string) | yes | |
party_id | body (string/null) | The customer (or give lead_id) | |
lead_id | body (string/null) | ||
contact_id | body (string/null) | ||
stage_id | body (string/null) | Default: the first open stage | |
value | body (string) | Expected value in the company's base currency | |
expected_close | body (string/null) | ||
source | body (string) | ||
owner_id | body (string/null) |
GET /api/crm/deals/{deal_id}
One deal: its stage history, notes, activities, tasks and the quote prepared from it.
| Field | Where | Required | Notes |
|---|---|---|---|
deal_id | path | yes |
PUT /api/crm/deals/{deal_id}
Change an open deal's title, value, expected close date, owner, contact or source.
| Field | Where | Required | Notes |
|---|---|---|---|
deal_id | path | yes | |
title | body (string) | yes | |
value | body (string) | ||
expected_close | body (string/null) | ||
owner_id | body (string/null) | ||
contact_id | body (string/null) | ||
source | body (string) |
POST /api/crm/deals/{deal_id}/move
Move a deal to another stage.
| Field | Where | Required | Notes |
|---|---|---|---|
deal_id | path | yes | |
stage_id | body (string) | yes | |
lost_reason | body (string) | Needed when moving to the lost stage |
POST /api/crm/deals/{deal_id}/quote
Prepare a sales quote DRAFT for the deal's customer.
| Field | Where | Required | Notes |
|---|---|---|---|
deal_id | path | yes | |
lines | body (array) | yes | |
doc_date | body (string/null) |
GET /api/crm/forecast
Pipeline forecast: open value per stage, weighted by each stage's chance, won / lost totals and the lost reasons.
GET /api/crm/leads
Leads (possible customers not yet in the books), newest first.
| Field | Where | Required | Notes |
|---|---|---|---|
status | query |
POST /api/crm/leads
Add a lead.
| Field | Where | Required | Notes |
|---|---|---|---|
name | body (string) | yes | The person |
organisation | body (string) | ||
phone | body (string) | ||
email | body (string) | ||
source | body (string) | Where the lead came from, e.g. | |
owner_id | body (string/null) | Member who owns the lead (default: you) |
GET /api/crm/leads/{lead_id}
One lead with its notes, activities, tasks and deals.
| Field | Where | Required | Notes |
|---|---|---|---|
lead_id | path | yes |
POST /api/crm/leads/{lead_id}/convert
Make the lead a customer (an explicit step): a new customer and a contact at it; its open deals move to the customer.
| Field | Where | Required | Notes |
|---|---|---|---|
lead_id | path | yes | |
code | body (string) | yes | The new customer's code |
name | body (string/null) | Customer name (default: the organisation, else the person) | |
terms_days | body (integer) |
POST /api/crm/leads/{lead_id}/status
Mark a lead qualified, or dropped with a reason.
| Field | Where | Required | Notes |
|---|---|---|---|
lead_id | path | yes | |
status | body (string) | yes | |
reason | body (string) | Why it was dropped (needed for dropped) |
POST /api/crm/notes/{ref_type}/{ref_id}
Add a note to a contact, lead or deal timeline (kept as written, with who and when).
| Field | Where | Required | Notes |
|---|---|---|---|
ref_type | path | yes | |
ref_id | path | yes | |
text | body (string) | yes |
GET /api/crm/parties
Customers / vendors you may see, with how many contacts and open deals each has.
| Field | Where | Required | Notes |
|---|---|---|---|
q | query |
GET /api/crm/parties/{party_id}/overview
Customer / vendor 360: contacts, deals, open tasks, recent activities, documents and the balance (overdue part too).
| Field | Where | Required | Notes |
|---|---|---|---|
party_id | path | yes | |
as_of | query |
GET /api/crm/stages
The company's pipeline stages in board order (the first look creates the starting set, which admins can rename).
PUT /api/crm/stages
Rename, reorder, add or close pipeline stages (owner / CFO).
| Field | Where | Required | Notes |
|---|---|---|---|
stages | body (array) | yes | All stages, in board order |
customisation
PUT /api/company/nav-tags
The company's own search words for menu items (owner / CFO); everyone in the company finds menus by them.
| Field | Where | Required | Notes |
|---|---|---|---|
nav_tags | body (object) | yes | {menu item id: [words]} for the whole company |
GET /api/labels
This company's renamed labels for a language: {key: label} — only the overrides.
| Field | Where | Required | Notes |
|---|---|---|---|
lang | query | ||
merged | query |
PUT /api/labels
Rename labels for this company and language (owner, CFO or a member allowed to customise).
| Field | Where | Required | Notes |
|---|---|---|---|
lang | query | ||
labels | body (object) | yes | {"menu.crm": "Customer Relations"} — null (or "") puts a label back to its default |
GET /api/labels/history
Who renamed which label, when, from what to what (newest first).
| Field | Where | Required | Notes |
|---|---|---|---|
lang | query | ||
key | query | ||
limit | query |
GET /api/user/ui-preferences
My menu order, colours, open groups, my names and words for menu items, plus the company's words.
PUT /api/user/ui-preferences
Save my whole menu layout (null = back to standard).
| Field | Where | Required | Notes |
|---|---|---|---|
menu_layout | body (object/null) | {order[], colors{group:{swatch,text,highlight}}, open{}, labels{key:text}, tags{id:[words]}}; null = standard |
POST /api/user/ui-preferences/collapse-all
Close every group of my menu.
POST /api/user/ui-preferences/colour
Give a group of MY menu a colour: a swatch, a text colour and / or a highlight background (must stay readable: 4.5:1).
| Field | Where | Required | Notes |
|---|---|---|---|
group | body (string) | yes | |
swatch | body (string/null) | ||
text | body (string/null) | ||
highlight | body (string/null) |
POST /api/user/ui-preferences/expand-all
Open every group of my menu.
POST /api/user/ui-preferences/move
Move one menu group of MY menu to a position (0 = top).
| Field | Where | Required | Notes |
|---|---|---|---|
group | body (string) | yes | |
position | body (integer) | yes | 0 = top |
current_order | body (array) | yes | The group ids of the menu as the person sees it now |
POST /api/user/ui-preferences/rename
Rename a menu item, form or field for me, or for the whole company (owner / CFO).
| Field | Where | Required | Notes |
|---|---|---|---|
id | body (string) | yes | The label key of the menu item, form or field (e.g. |
text | body (string) | Empty = back to the standard name | |
scope | body (string) | ||
lang | body (string) |
POST /api/user/ui-preferences/reset
Reset to standard: put MY menu (and / or my names and words) back to the company standard.
| Field | Where | Required | Notes |
|---|---|---|---|
scope | body (string) |
POST /api/user/ui-preferences/tags
Add a word people search with for a menu item (any language), for me or for the whole company (owner / CFO).
| Field | Where | Required | Notes |
|---|---|---|---|
id | body (string) | yes | |
tag | body (string) | yes | A word people search with, any language (e.g. |
scope | body (string) |
POST /api/user/ui-preferences/tags/remove
Remove a search word from a menu item (mine, or the company's: owner / CFO).
| Field | Where | Required | Notes |
|---|---|---|---|
id | body (string) | yes | |
tag | body (string) | yes | A word people search with, any language (e.g. |
scope | body (string) |
dashboards
GET /api/dashboards
Your dashboards (default first) and the ones shared with your role.
GET /api/dashboards/data/{source}
One widget's data: a KPI value, a series of points or a table, with the comparison (previous period / previous year) and a drill-down link.
| Field | Where | Required | Notes |
|---|---|---|---|
source | path | yes | |
period | query | ||
start | query | ||
end | query | ||
compare | query | ||
limit | query | ||
accounts | query | Comma-separated account codes (cash_balance) | |
report_id | query | A saved report (saved_report, saved_report_value, saved_report_series) | |
column | query | saved_report_value: the report column to show as one figure | |
label | query | saved_report_series: the column for the labels | |
value | query | saved_report_series: the column for the values |
GET /api/dashboards/sources
The data sources your role may put on a dashboard (revenue by month, expenses by account, AR/AP aging, cash, top customers, approvals waiting, drafts, net profit, books balanced…).
DELETE /api/dashboards/{dashboard_id}
Delete one of your dashboards.
| Field | Where | Required | Notes |
|---|---|---|---|
dashboard_id | path | yes |
GET /api/dashboards/{dashboard_id}
One dashboard you own or that is shared with your role.
| Field | Where | Required | Notes |
|---|---|---|---|
dashboard_id | path | yes |
PUT /api/dashboards/{dashboard_id}
Create (a new id; 201) or replace (your own; 200) a dashboard: name, widgets (drag/resize/rename/minimise state included), default flag, roles it is shared with.
| Field | Where | Required | Notes |
|---|---|---|---|
dashboard_id | path | yes | |
name | body (string) | yes | |
widgets | body (array) | ||
shared_roles | body (array) | Roles that may open (not change) it — owner/CFO only | |
is_default | body (boolean) |
GET /api/dashboards/{dashboard_id}/data
Every widget's data in one call.
| Field | Where | Required | Notes |
|---|---|---|---|
dashboard_id | path | yes | |
start | query | ||
end | query |
documents
GET /api/documents
Sales (side=customer) or purchase (side=vendor) documents, newest first; filter by type, status and party code.
| Field | Where | Required | Notes |
|---|---|---|---|
side | query | ||
doc_type | query | ||
status | query | ||
party | query |
POST /api/documents
Prepare a DRAFT document: a sales invoice or purchase bill (lines), a customer receipt or vendor payment (amount + bank account + which invoices / bills it settles), a quote, order, delivery or goods-received note.
| Field | Where | Required | Notes |
|---|---|---|---|
branch | body (string/null) | Branch / project / cost-centre code (optional) | |
project | body (string/null) | Branch / project / cost-centre code (optional) | |
cost_centre | body (string/null) | Branch / project / cost-centre code (optional) | |
party | body (string) | yes | Customer or vendor code |
doc_date | body (string) | yes | |
due_date | body (string/null) | ||
currency | body (string/null) | ||
fx_rate | body (number/string/null) | ||
lines | body (array) | Invoices, bills, notes, quotes, orders, notes | |
amount | body (number/string/null) | Receipts and payments: the amount | |
bank_account | body (string/null) | Receipts and payments: the cash / bank account code | |
allocations | body (array) | Receipts / payments: which invoices / bills it settles | |
memo | body (string) | ||
reference | body (string) | Customer PO number, vendor bill number, cheque number … | |
warehouse | body (string/null) | ||
source_id | body (string/null) | The document this one is made from | |
instrument_type | body (string) | Receipts / payments: how the money moved | |
instrument_ref | body (string) | Cheque number, transfer / UTR reference | |
instrument_date | body (string/null) | Cheque date | |
clearing_date | body (string/null) | Date the bank cleared it | |
deductions | body (array) | Receipts / payments: tax withheld, bank charges (change the bank amount, not the customer / vendor amount) | |
vendor_invoice_no | body (string) | Purchase bills: the vendor's own invoice number (booked once per vendor) | |
vendor_invoice_date | body (string/null) | Purchase bills: the vendor's invoice date | |
doc_type | body (string) | yes |
GET /api/documents-setup
Is the company ready for invoices and bills (control accounts, posting rules, numbering)?
POST /api/documents-setup
Make the company ready for sales and purchase documents (owner or CFO): customer and vendor control accounts, default income / expense / tax accounts; seeds posting rules, approval rules, numbering and tax codes.
| Field | Where | Required | Notes |
|---|---|---|---|
receivable | body (string) | yes | Customer control account code (a fresh asset account) |
payable | body (string) | yes | Vendor control account code (a fresh liability account) |
income | body (string) | yes | Default sales income account |
expense | body (string) | yes | Default purchase / expense account |
output_tax | body (string) | yes | Sales tax payable account |
input_tax | body (string) | yes | Input tax (recoverable) account |
GET /api/documents-setup/cash-accounts
The company's registered bank and cash accounts, for receipts and payments (a strict choice, not free text).
POST /api/documents-setup/control-accounts
Make one more account a receivable / payable control account (owner or CFO), e.g.
| Field | Where | Required | Notes |
|---|---|---|---|
code | body (string) | yes | |
kind | body (string) | yes |
GET /api/documents/{doc_id}
One document with lines, allocations, deductions, what is paid / still open, the tax ids the active tax pack asks for, and whether you may approve it (you_made_it, you_can_self_approve).
| Field | Where | Required | Notes |
|---|---|---|---|
doc_id | path | yes |
PUT /api/documents/{doc_id}
Replace a DRAFT's content (only drafts change; send a submitted one back first).
| Field | Where | Required | Notes |
|---|---|---|---|
doc_id | path | yes | |
branch | body (string/null) | Branch / project / cost-centre code (optional) | |
project | body (string/null) | Branch / project / cost-centre code (optional) | |
cost_centre | body (string/null) | Branch / project / cost-centre code (optional) | |
party | body (string) | yes | Customer or vendor code |
doc_date | body (string) | yes | |
due_date | body (string/null) | ||
currency | body (string/null) | ||
fx_rate | body (number/string/null) | ||
lines | body (array) | Invoices, bills, notes, quotes, orders, notes | |
amount | body (number/string/null) | Receipts and payments: the amount | |
bank_account | body (string/null) | Receipts and payments: the cash / bank account code | |
allocations | body (array) | Receipts / payments: which invoices / bills it settles | |
memo | body (string) | ||
reference | body (string) | Customer PO number, vendor bill number, cheque number … | |
warehouse | body (string/null) | ||
source_id | body (string/null) | The document this one is made from | |
instrument_type | body (string) | Receipts / payments: how the money moved | |
instrument_ref | body (string) | Cheque number, transfer / UTR reference | |
instrument_date | body (string/null) | Cheque date | |
clearing_date | body (string/null) | Date the bank cleared it | |
deductions | body (array) | Receipts / payments: tax withheld, bank charges (change the bank amount, not the customer / vendor amount) | |
vendor_invoice_no | body (string) | Purchase bills: the vendor's own invoice number (booked once per vendor) | |
vendor_invoice_date | body (string/null) | Purchase bills: the vendor's invoice date |
POST /api/documents/{doc_id}/approve
Approve a submitted document (never your own; your role's limit must cover the amount).
| Field | Where | Required | Notes |
|---|---|---|---|
doc_id | path | yes | |
note | body (string) | ||
self_review | body (string/null) | Only when YOU made it and you are the only person who may approve it: your written review, e.g. |
POST /api/documents/{doc_id}/cancel
Cancel a document that is not posted (a posted one is corrected by a credit / debit note).
| Field | Where | Required | Notes |
|---|---|---|---|
doc_id | path | yes | |
reason | body (string) | yes |
POST /api/documents/{doc_id}/copy
Make the next document from this one as a DRAFT (quote → order → invoice, PO → goods received → bill).
| Field | Where | Required | Notes |
|---|---|---|---|
doc_id | path | yes | |
doc_type | body (string) | yes | The next document: order from quote, invoice from order, bill from PO … |
doc_date | body (string) | yes |
POST /api/documents/{doc_id}/credit-note
DRAFT credit note for a posted sales invoice (whole invoice, or the lines given); it settles the invoice when posted.
| Field | Where | Required | Notes |
|---|---|---|---|
doc_id | path | yes | |
doc_date | body (string) | yes | |
reason | body (string) | yes | |
lines | body (array/null) | Leave out for the whole invoice / bill |
POST /api/documents/{doc_id}/debit-note
DRAFT debit note for a posted purchase bill (returns, price corrections).
| Field | Where | Required | Notes |
|---|---|---|---|
doc_id | path | yes | |
doc_date | body (string) | yes | |
reason | body (string) | yes | |
lines | body (array/null) | Leave out for the whole invoice / bill |
POST /api/documents/{doc_id}/post
Post an APPROVED document to the books (owner, CFO or accountant): builds its journal entry, numbers it, settles what it allocates.
| Field | Where | Required | Notes |
|---|---|---|---|
doc_id | path | yes |
GET /api/documents/{doc_id}/print
The document as a printable page (HTML) or PDF: letterhead, DRAFT mark until posted, tax ids with the active tax pack's labels, lines and totals (receipts and payments: instrument, deductions, net to bank).
| Field | Where | Required | Notes |
|---|---|---|---|
doc_id | path | yes | |
format | query |
POST /api/documents/{doc_id}/reject
Send a submitted or approved document back to its maker as a draft, with the reason.
| Field | Where | Required | Notes |
|---|---|---|---|
doc_id | path | yes | |
reason | body (string) | yes |
POST /api/documents/{doc_id}/submit
Send a draft for approval: the people who may approve it get a To-Do (and an e-mail when the company has it on).
| Field | Where | Required | Notes |
|---|---|---|---|
doc_id | path | yes |
GET /api/items
Items and services with prices and default tax code.
POST /api/items
Add an item or service (owner, CFO, accountant, clerk, sales or purchase).
| Field | Where | Required | Notes |
|---|---|---|---|
code | body (string) | yes | Never changes |
name | body (string) | yes | |
unit | body (string) | ||
sale_price | body (number/string) | ||
purchase_price | body (number/string) | ||
tax_code | body (string/null) | Default tax code | |
income | body (string/null) | Own income account (else the default) | |
expense | body (string/null) | Own expense account (else the default) |
GET /api/parties
Customers (side=customer), vendors (side=vendor) or both.
| Field | Where | Required | Notes |
|---|---|---|---|
side | query |
POST /api/parties
Add a customer, a vendor or both (owner, CFO, accountant, clerk, sales or purchase).
| Field | Where | Required | Notes |
|---|---|---|---|
code | body (string) | yes | Never changes |
name | body (string) | yes | |
customer | body (boolean) | ||
vendor | body (boolean) | ||
terms_days | body (integer) | Payment terms in days (sets due dates) | |
currency | body (string/null) | ||
tax_number | body (string) | ||
email | body (string) | ||
phone | body (string) |
GET /api/tax-codes
The company's tax codes and rates.
foreign-exchange
GET /api/fx/rates
The rate table (base-currency units per 1 foreign unit), by currency and date.
| Field | Where | Required | Notes |
|---|---|---|---|
currency | query | Currency code, e.g. | |
start | query | ||
end | query |
PUT /api/fx/rates
Record or correct the rate of a currency on a date (owner, CFO or accountant).
| Field | Where | Required | Notes |
|---|---|---|---|
currency | body (string) | yes | |
rate_date | body (string) | yes | |
rate | body (number/string) | yes | Base-currency units per 1 unit of the currency |
note | body (string) | Why (required when you change a rate that was fetched automatically) |
POST /api/fx/rates/fetch
The company's rate for a currency on a date: kept if already there, else looked up automatically from public sources (only the currency code and date go out) and stored with its source and time; 'unavailable' rather than an invented rate.
| Field | Where | Required | Notes |
|---|---|---|---|
currency | body (string) | yes | |
rate_date | body (string) | yes |
GET /api/fx/rates/{currency}/on
The rate in force on a day (the latest on or before it); refused when there is none.
| Field | Where | Required | Notes |
|---|---|---|---|
currency | path | yes | |
date | query | yes |
GET /api/fx/revaluations
Revaluations, newest first; filter by status.
| Field | Where | Required | Notes |
|---|---|---|---|
status | query |
POST /api/fx/revaluations
Prepare the period-end revaluation as DRAFTS (one per foreign currency with something to adjust).
| Field | Where | Required | Notes |
|---|---|---|---|
as_of | body (string) | yes | |
currency | body (string/null) | Default: every foreign currency |
GET /api/fx/revaluations/preview
What a revaluation on the date would do — nothing is written: per currency the closing rate, every open item and bank balance with its adjustment, and the net unrealised gain (+) / loss (−).
| Field | Where | Required | Notes |
|---|---|---|---|
as_of | query | yes | |
currency | query | Currency code, e.g. |
GET /api/fx/revaluations/{revaluation_id}
One revaluation with every line it revalued, its entry and (once posted) its reversal.
| Field | Where | Required | Notes |
|---|---|---|---|
revaluation_id | path | yes |
POST /api/fx/revaluations/{revaluation_id}/cancel
Drop a revaluation that is not posted (it stays as cancelled; its draft entry can never post).
| Field | Where | Required | Notes |
|---|---|---|---|
revaluation_id | path | yes |
POST /api/fx/revaluations/{revaluation_id}/post
Post an APPROVED revaluation (owner, CFO or accountant) together with its reversal dated the next day.
| Field | Where | Required | Notes |
|---|---|---|---|
revaluation_id | path | yes |
GET /api/fx/settings
The exchange gain/loss accounts (realised and unrealised); null when foreign exchange is not set up.
PUT /api/fx/settings
Choose the exchange gain/loss accounts (owner or CFO; postable income/expense accounts).
| Field | Where | Required | Notes |
|---|---|---|---|
realised_gain | body (string) | yes | |
realised_loss | body (string) | yes | |
unrealised_gain | body (string/null) | Default: the realised gain account | |
unrealised_loss | body (string/null) | Default: the realised loss account |
hub
GET /api/hub/meetings
Meetings you may see (company-wide ones and those you are invited to), newest first.
POST /api/hub/meetings
Plan a meeting with its agenda and people (you are the organizer).
| Field | Where | Required | Notes |
|---|---|---|---|
title | body (string) | yes | |
starts_at | body (string) | yes | |
ends_at | body (string/null) | ||
purpose | body (string) | ||
location | body (string) | ||
visibility | body (string) | participants = only invited people see it, also in search | |
participants | body (array) | Member user ids | |
minute_taker | body (string/null) | ||
agenda | body (array) |
GET /api/hub/meetings/{meeting_id}
One meeting: agenda, people, discussion, minutes, decisions and their tasks.
| Field | Where | Required | Notes |
|---|---|---|---|
meeting_id | path | yes |
POST /api/hub/meetings/{meeting_id}/agenda
Add an agenda point (organizer or minute-taker).
| Field | Where | Required | Notes |
|---|---|---|---|
meeting_id | path | yes | |
title | body (string) | yes | |
details | body (string) | ||
owner_id | body (string/null) | The member who presents this point | |
ref_type | body (string/null) | ||
ref_id | body (string/null) | A transaction this point is about |
POST /api/hub/meetings/{meeting_id}/cancel
Cancel a planned meeting (organizer).
| Field | Where | Required | Notes |
|---|---|---|---|
meeting_id | path | yes |
POST /api/hub/meetings/{meeting_id}/decisions
Record a decision and its action items; each action item becomes a task (To-Do) for its person.
| Field | Where | Required | Notes |
|---|---|---|---|
meeting_id | path | yes | |
text | body (string) | yes | |
tasks | body (array) | Action items: each becomes a task (To-Do) for its person |
PUT /api/hub/meetings/{meeting_id}/minutes
Write the minutes (organizer or minute-taker); final=true freezes them (organizer).
| Field | Where | Required | Notes |
|---|---|---|---|
meeting_id | path | yes | |
minutes | body (string) | yes | |
final | body (boolean) | Final minutes never change again (organizer only) |
POST /api/hub/meetings/{meeting_id}/people
Invite members (organizer or minute-taker).
| Field | Where | Required | Notes |
|---|---|---|---|
meeting_id | path | yes | |
user_ids | body (array) | yes | |
part | body (string) |
POST /api/hub/meetings/{meeting_id}/posts
Write in the meeting's discussion; tag members with mentions (they get a notice).
| Field | Where | Required | Notes |
|---|---|---|---|
meeting_id | path | yes | |
text | body (string) | yes | |
mentions | body (array) | Member user ids tagged (@person): they get a notice |
GET /api/hub/my-day
What needs you today: tasks overdue / today / this week, meetings today and tomorrow, unread mentions, approvals waiting.
GET /api/hub/tasks
Tasks for you and tasks you gave.
| Field | Where | Required | Notes |
|---|---|---|---|
status | query |
POST /api/hub/tasks
Give a task to a member (optionally about a transaction).
| Field | Where | Required | Notes |
|---|---|---|---|
title | body (string) | yes | |
assignee_id | body (string) | yes | |
details | body (string) | ||
due_date | body (string/null) | ||
ref_type | body (string/null) | ||
ref_id | body (string/null) |
POST /api/hub/tasks/{task_id}/finish
Mark your task done (with a note), or cancel a task you gave.
| Field | Where | Required | Notes |
|---|---|---|---|
task_id | path | yes | |
status | body (string) | yes | |
note | body (string) |
GET /api/hub/threads/{ref_type}/{ref_id}
The discussion on a transaction or a customer / vendor (for people who may open it).
| Field | Where | Required | Notes |
|---|---|---|---|
ref_type | path | yes | |
ref_id | path | yes |
POST /api/hub/threads/{ref_type}/{ref_id}/posts
Write in a transaction's / customer's / vendor's discussion; tag people (they get a notice).
| Field | Where | Required | Notes |
|---|---|---|---|
ref_type | path | yes | |
ref_id | path | yes | |
text | body (string) | yes | |
mentions | body (array) | Member user ids tagged (they must be able to open the record) |
import
GET /api/import/batches
Imports of this company, newest first.
POST /api/import/batches
Upload an import package (JSON).
| Field | Where | Required | Notes |
|---|---|---|---|
package | body (object) | yes | The canonical import package (format isoerp-next-import, version 1) |
label | body (string) | A name for this import, e.g. |
GET /api/import/batches/{batch_id}
One import: status, what the file contains, errors and skipped records, mapping, progress, verification, history.
| Field | Where | Required | Notes |
|---|---|---|---|
batch_id | path | yes | |
include_problems | query |
POST /api/import/batches/{batch_id}/discard
Take back an import that was never posted: every draft, account, party and added person it created is removed.
| Field | Where | Required | Notes |
|---|---|---|---|
batch_id | path | yes | |
reason | body (string) |
POST /api/import/batches/{batch_id}/explain
Write down why one account differs from the old system's trial balance (a person's judgement; it is kept with the import).
| Field | Where | Required | Notes |
|---|---|---|---|
batch_id | path | yes | |
account | body (string) | yes | |
reason | body (string) | yes | Why the new books differ from the old system's trial balance for this account |
PUT /api/import/batches/{batch_id}/mapping
How to read the package: old role → new role, account type corrections, suspense account, which old years to lock.
| Field | Where | Required | Notes |
|---|---|---|---|
batch_id | path | yes | |
roles | body (object) | Old role name → cfo, accountant, clerk, sales, purchase, warehouse, hr or viewer (never owner) | |
account_types | body (object) | Account code → asset, liability, equity, income or expense | |
suspense_account | body (string/null) | A postable account that absorbs an unbalanced opening entry | |
lock_closed_before | body (string/null) | Lock the accounting periods that end before this date once the import is posted |
POST /api/import/batches/{batch_id}/party-openings
After staging: make one DRAFT opening document per customer / vendor balance (invoice, credit note, bill or debit note marked 'Opening balance from <old system>'); they are submitted with the import and approved + posted by another person.
| Field | Where | Required | Notes |
|---|---|---|---|
batch_id | path | yes |
POST /api/import/batches/{batch_id}/post
A DIFFERENT authorised person approves and posts the submitted entries (or the reversal entries of a reversing import).
| Field | Where | Required | Notes |
|---|---|---|---|
batch_id | path | yes | |
limit | body (integer) |
POST /api/import/batches/{batch_id}/reverse
Take back a POSTED import with reversal entries (another person posts them with the post step).
| Field | Where | Required | Notes |
|---|---|---|---|
batch_id | path | yes | |
reversal_date | body (string) | yes | |
reason | body (string) | yes | |
limit | body (integer) |
POST /api/import/batches/{batch_id}/stage
Create the accounts, parties, items and every voucher as DRAFTS (nothing is posted).
| Field | Where | Required | Notes |
|---|---|---|---|
batch_id | path | yes | |
max_vouchers | body (integer) | How many vouchers to create in this call (call again until done) |
POST /api/import/batches/{batch_id}/submit
Send every staged draft for approval (the person who staged it).
| Field | Where | Required | Notes |
|---|---|---|---|
batch_id | path | yes | |
limit | body (integer) | ||
acknowledge_no_control_total | body (boolean) | Accept that there is no old trial balance to check against |
GET /api/import/batches/{batch_id}/verification
Compare the staged books with the package and with the old system's own trial balance, account by account.
| Field | Where | Required | Notes |
|---|---|---|---|
batch_id | path | yes |
POST /api/import/legacy
Upload rows copied from the OLD ISOERP (a copy of its database, never the live one).
| Field | Where | Required | Notes |
|---|---|---|---|
rows | body (object) | yes | Rows copied from the OLD ISOERP, keyed by table name (see EXTRACT_SQL): HeadofAccount, ControlAccount, SubControlAccount, ChartOfAccount, Transaction, TransactionDetails, Customer, Supplier, Branches, AbpUsers |
company_name | body (string) | yes | |
base_currency | body (string) | ||
country | body (string) | ||
extracted_at | body (string) | ||
head_types | body (object) | Old head-of-account code → asset, liability, equity, income or expense (only for heads whose title says nothing) | |
include_opening_vouchers | body (boolean) | ||
count_submitted | body (boolean/null) | Old vouchers stored as 'Submitted': true = they are part of the books, false = leave them out. | |
orphan_account | body (string/null) | ||
party_control | body (object/null) | Old control accounts whose lines name customers / vendors: {"receivable": [codes], "payable": [codes], "accept_unassigned": false}. | |
trial_balance | body (object/null) | The old system's own trial balance: {as_of, rows: [{account, debit, credit}]} | |
label | body (string) |
inventory
GET /api/inventory/settings
The inventory accounts (GRNI, COGS, adjustment, price variance), the default warehouse and whether negative stock is allowed; null when inventory is not set up yet.
PATCH /api/inventory/settings
Change the default COGS / adjustment / price-variance accounts, the default warehouse or whether negative stock is allowed (owner or CFO).
| Field | Where | Required | Notes |
|---|---|---|---|
cogs | body (string/null) | ||
adjustment | body (string/null) | ||
price_variance | body (string/null) | ||
default_warehouse | body (string/null) | Warehouse code | |
allow_negative_stock | body (boolean/null) |
POST /api/inventory/setup
Turn inventory on (owner or CFO; the plan must include inventory): GRNI, COGS, adjustment and price-variance account codes and the default warehouse (created if new).
| Field | Where | Required | Notes |
|---|---|---|---|
grni | body (string) | yes | Goods received not invoiced: a fresh liability account (becomes a control account) |
cogs | body (string) | yes | Default cost of goods sold account |
adjustment | body (string) | yes | Default stock gain/loss account |
price_variance | body (string) | yes | Purchase price variance account |
warehouse_code | body (string/null) | Default warehouse code (created if new) | |
warehouse_name | body (string/null) | ||
allow_negative_stock | body (boolean) |
GET /api/items/{code}/stock
An item's cost method, COGS account, reorder level / quantity and quantity on hand.
| Field | Where | Required | Notes |
|---|---|---|---|
code | path | yes |
PATCH /api/items/{code}/stock
Set an item's cost method ('average' or 'fifo' — only before its first movement), its own COGS account, reorder level and reorder quantity (owner, CFO, accountant or warehouse).
| Field | Where | Required | Notes |
|---|---|---|---|
code | path | yes | |
cost_method | body (string/null) | Only before the item's first movement | |
cogs | body (string/null) | The item's own COGS account code | |
reorder_level | body (number/string/null) | ||
reorder_qty | body (number/string/null) |
GET /api/stock-docs
Stock adjustments and transfers, newest first; filter by kind and status.
| Field | Where | Required | Notes |
|---|---|---|---|
kind | query | ||
status | query |
POST /api/stock-docs/adjustments
Prepare a DRAFT stock adjustment in one warehouse: + found / − lost per item (stock coming in may carry a unit cost).
| Field | Where | Required | Notes |
|---|---|---|---|
branch | body (string/null) | Branch / project / cost-centre code (optional) | |
project | body (string/null) | Branch / project / cost-centre code (optional) | |
cost_centre | body (string/null) | Branch / project / cost-centre code (optional) | |
doc_date | body (string) | yes | |
warehouse | body (string) | yes | |
lines | body (array) | yes | |
counter_account | body (string/null) | Where the gain/loss goes (default: the adjustment account) | |
reason | body (string) |
POST /api/stock-docs/transfers
Prepare a DRAFT transfer between two warehouses (quantities above zero; stock moves at its cost).
| Field | Where | Required | Notes |
|---|---|---|---|
branch | body (string/null) | Branch / project / cost-centre code (optional) | |
project | body (string/null) | Branch / project / cost-centre code (optional) | |
cost_centre | body (string/null) | Branch / project / cost-centre code (optional) | |
doc_date | body (string) | yes | |
from_warehouse | body (string) | yes | |
to_warehouse | body (string) | yes | |
lines | body (array) | yes | |
reason | body (string) |
GET /api/stock-docs/{stock_doc_id}
One stock adjustment or transfer with its lines, status, maker, approver and journal number once posted.
| Field | Where | Required | Notes |
|---|---|---|---|
stock_doc_id | path | yes |
POST /api/stock-docs/{stock_doc_id}/approve
Approve a submitted stock document.
| Field | Where | Required | Notes |
|---|---|---|---|
stock_doc_id | path | yes | |
note | body (string) |
POST /api/stock-docs/{stock_doc_id}/cancel
Cancel a stock document that is not posted, with a reason (it stays in history).
| Field | Where | Required | Notes |
|---|---|---|---|
stock_doc_id | path | yes | |
reason | body (string) | yes |
POST /api/stock-docs/{stock_doc_id}/post
Post an APPROVED stock document: moves the stock at cost and posts its journal entry (SA-/ST- number).
| Field | Where | Required | Notes |
|---|---|---|---|
stock_doc_id | path | yes |
POST /api/stock-docs/{stock_doc_id}/reject
Send a submitted or approved stock document back to draft, with a reason.
| Field | Where | Required | Notes |
|---|---|---|---|
stock_doc_id | path | yes | |
reason | body (string) | yes |
POST /api/stock-docs/{stock_doc_id}/submit
Send a draft stock document for approval.
| Field | Where | Required | Notes |
|---|---|---|---|
stock_doc_id | path | yes |
GET /api/warehouses
Every warehouse (store, shop, yard) of this company, closed ones too.
POST /api/warehouses
Add a warehouse (owner, CFO, accountant or warehouse; the plan must include inventory).
| Field | Where | Required | Notes |
|---|---|---|---|
code | body (string) | yes | Never changes |
name | body (string) | yes | |
branch | body (string/null) | Branch code its stock postings belong to (optional) |
GET /api/warehouses/{code}
One warehouse by code.
| Field | Where | Required | Notes |
|---|---|---|---|
code | path | yes |
PATCH /api/warehouses/{code}
Rename, close (active=false — only when it holds no stock) or reopen a warehouse.
| Field | Where | Required | Notes |
|---|---|---|---|
code | path | yes | |
name | body (string/null) | ||
active | body (boolean/null) | false = close (only when it holds no stock); true = reopen |
GET /api/warehouses/{code}/location
A warehouse's place and its weather now / next days (cached; 'unavailable' when the service does not answer).
| Field | Where | Required | Notes |
|---|---|---|---|
code | path | yes |
PUT /api/warehouses/{code}/location
Where a warehouse / depot / site is (from the place search): for weather, wind and maps (owner, CFO, accountant, warehouse).
| Field | Where | Required | Notes |
|---|---|---|---|
code | path | yes | |
place | body (string) | The place as chosen from the place search | |
latitude | body (number/null) | ||
longitude | body (number/null) | ||
country | body (string/null) |
journal
GET /api/approvals/context/{ref_type}/{ref_id}
For one entry / document: did you make it, may you approve it yourself as the ONLY possible approver right now, and who else may approve it (screens hide Approve from the maker unless the sole-approver step applies).
| Field | Where | Required | Notes |
|---|---|---|---|
ref_type | path | yes | |
ref_id | path | yes |
GET /api/approvals/inbox
Entries waiting for YOUR approval: submitted, not made by you, and within your approval limit.
GET /api/approvals/mine
What I made that is not finished yet (drafts, waiting for approval, waiting to be posted) and whom it waits on — including drafts the assistant (Star) or WhatsApp prepared for me.
GET /api/entries
Journal entries, newest first, 50 per page by default; filter by status and date.
| Field | Where | Required | Notes |
|---|---|---|---|
status | query | ||
date_from | query | ||
date_to | query | ||
page | query | ||
page_size | query |
POST /api/entries
Create a journal entry as a draft.
| Field | Where | Required | Notes |
|---|---|---|---|
entry_date | body (string) | yes | |
memo | body (string) | ||
currency | body (string/null) | Defaults to the company's base currency | |
lines | body (array) | yes | |
branch | body (string/null) | Default branch for lines that name none | |
project | body (string/null) | Default project for lines that name none | |
cost_centre | body (string/null) | Default cost centre for lines that name none |
GET /api/entries/{entry_id}
One entry with its lines and its full approval history (who, what, when, why).
| Field | Where | Required | Notes |
|---|---|---|---|
entry_id | path | yes |
PATCH /api/entries/{entry_id}
Change a DRAFT entry: date, memo, currency and/or all its lines (it must still balance).
| Field | Where | Required | Notes |
|---|---|---|---|
entry_id | path | yes | |
entry_date | body (string/null) | ||
memo | body (string/null) | ||
currency | body (string/null) | ||
lines | body (array/null) | Replaces every line | |
branch | body (string/null) | Default branch for new lines that name none | |
project | body (string/null) | ||
cost_centre | body (string/null) |
POST /api/entries/{entry_id}/approve
Approve a submitted entry.
| Field | Where | Required | Notes |
|---|---|---|---|
entry_id | path | yes | |
note | body (string) | ||
self_review | body (string/null) | Only when YOU made it and you are the only person who may approve it: your written review, e.g. |
POST /api/entries/{entry_id}/post
Post an approved entry to the books: it gets its number and joins the tamper-evident chain.
| Field | Where | Required | Notes |
|---|---|---|---|
entry_id | path | yes |
POST /api/entries/{entry_id}/reject
Send a submitted or approved entry back to draft, with a reason.
| Field | Where | Required | Notes |
|---|---|---|---|
entry_id | path | yes | |
reason | body (string) | yes |
POST /api/entries/{entry_id}/reverse
Correct a posted entry: creates an opposite DRAFT that goes through the same approval before it posts.
| Field | Where | Required | Notes |
|---|---|---|---|
entry_id | path | yes | |
entry_date | body (string) | yes | |
reason | body (string) | yes |
POST /api/entries/{entry_id}/submit
Send a draft for approval.
| Field | Where | Required | Notes |
|---|---|---|---|
entry_id | path | yes |
learning
GET /api/lms/access
Is Learning on for this company, and what is my part in it (admin / instructor / none).
PATCH /api/lms/assessments/{assessment_id}
Change or publish a quiz (only before any learner has taken it).
| Field | Where | Required | Notes |
|---|---|---|---|
assessment_id | path | yes | |
title | body (string/null) | ||
pass_mark | body (integer/null) | ||
max_attempts | body (integer/null) | ||
required | body (boolean/null) | ||
status | body (string/null) | ||
questions | body (array/null) |
GET /api/lms/certificates
Certificates issued (admins: all; instructors: their courses).
| Field | Where | Required | Notes |
|---|---|---|---|
course_id | query |
GET /api/lms/certificates/chain-check
Re-check every certificate this company issued: hashes, links between them, signatures, no gaps.
GET /api/lms/certificates/{certificate_id}
One certificate with its public verification link and QR code (to print).
| Field | Where | Required | Notes |
|---|---|---|---|
certificate_id | path | yes |
POST /api/lms/certificates/{certificate_id}/revoke
Revoke a certificate, with the reason (Learning admins).
| Field | Where | Required | Notes |
|---|---|---|---|
certificate_id | path | yes | |
reason | body (string) | yes |
GET /api/lms/courses
Courses (admins: all; instructors: the ones they teach) with enrolled and passed counts.
| Field | Where | Required | Notes |
|---|---|---|---|
status | query |
POST /api/lms/courses
Create a course as a draft (Learning admins).
| Field | Where | Required | Notes |
|---|---|---|---|
code | body (string) | yes | Short code, e.g. |
title | body (string) | yes | |
description | body (string) | ||
category | body (string) | ||
level | body (string) | ||
language | body (string) | ||
self_enrol | body (boolean) | Signed-in adults may join by themselves | |
certificate_enabled | body (boolean) | ||
fee_item | body (string/null) | Item code used when a tuition invoice is drafted |
GET /api/lms/courses/{course_id}
One course: modules, lessons, assessments with questions and answers, classes, instructors, announcements.
| Field | Where | Required | Notes |
|---|---|---|---|
course_id | path | yes |
PATCH /api/lms/courses/{course_id}
Change a course; publish (needs a lesson) or archive it.
| Field | Where | Required | Notes |
|---|---|---|---|
course_id | path | yes | |
code | body (string/null) | ||
title | body (string/null) | ||
description | body (string/null) | ||
category | body (string/null) | ||
level | body (string/null) | ||
language | body (string/null) | ||
status | body (string/null) | ||
self_enrol | body (boolean/null) | ||
certificate_enabled | body (boolean/null) | ||
fee_item | body (string/null) |
POST /api/lms/courses/{course_id}/announcements
Post an announcement to a course's learners (or one class).
| Field | Where | Required | Notes |
|---|---|---|---|
course_id | path | yes | |
title | body (string) | yes | |
body | body (string) | ||
cohort_id | body (string/null) |
POST /api/lms/courses/{course_id}/assessments
Add a quiz (multiple choice, true/false, short answer) with its pass mark and allowed attempts, as a draft.
| Field | Where | Required | Notes |
|---|---|---|---|
course_id | path | yes | |
title | body (string) | yes | |
pass_mark | body (integer) | Percent needed to pass | |
max_attempts | body (integer) | ||
required | body (boolean) | Must be passed to complete the course | |
questions | body (array) |
POST /api/lms/courses/{course_id}/cohorts
Add a class (cohort / batch) to a course.
| Field | Where | Required | Notes |
|---|---|---|---|
course_id | path | yes | |
name | body (string) | yes | |
starts_on | body (string/null) | ||
ends_on | body (string/null) |
GET /api/lms/courses/{course_id}/enrolments
Learners of a course with their status and progress.
| Field | Where | Required | Notes |
|---|---|---|---|
course_id | path | yes |
GET /api/lms/courses/{course_id}/gradebook
Gradebook: per learner progress, best score and attempts per quiz, attendance and certificate.
| Field | Where | Required | Notes |
|---|---|---|---|
course_id | path | yes |
PUT /api/lms/courses/{course_id}/instructors
Who teaches this course (members with the instructor part).
| Field | Where | Required | Notes |
|---|---|---|---|
course_id | path | yes | |
user_ids | body (array) |
POST /api/lms/courses/{course_id}/modules
Add a module (a chapter) to a course.
| Field | Where | Required | Notes |
|---|---|---|---|
course_id | path | yes | |
title | body (string) | yes |
POST /api/lms/courses/{course_id}/modules/{module_id}/lessons
Add a lesson to a module: text, or a link to a file or video (https).
| Field | Where | Required | Notes |
|---|---|---|---|
course_id | path | yes | |
module_id | path | yes | |
title | body (string) | yes | |
kind | body (string) | ||
body | body (string) | ||
link_url | body (string/null) | https link of the file or video | |
required | body (boolean) |
GET /api/lms/courses/{course_id}/sessions
Class sessions of a course with how many attended.
| Field | Where | Required | Notes |
|---|---|---|---|
course_id | path | yes |
POST /api/lms/courses/{course_id}/sessions
Plan a class session (for the whole course or one class).
| Field | Where | Required | Notes |
|---|---|---|---|
course_id | path | yes | |
title | body (string) | yes | |
starts_at | body (string) | yes | |
ends_at | body (string/null) | ||
location | body (string) | ||
cohort_id | body (string/null) | Only this class; empty = everyone in the course |
POST /api/lms/enrolments
Enrol a learner in a published course (a learner under 18 needs the guardian's enrolment consent first).
| Field | Where | Required | Notes |
|---|---|---|---|
learner_id | body (string) | yes | |
course_id | body (string) | yes | |
cohort_id | body (string/null) |
POST /api/lms/enrolments/{enrolment_id}/certificate
Issue the certificate of a PASSED course: number, tamper-evident public code and QR.
| Field | Where | Required | Notes |
|---|---|---|---|
enrolment_id | path | yes |
POST /api/lms/enrolments/{enrolment_id}/tuition-invoice
Draft the tuition invoice for an enrolment (a DRAFT sales invoice; a person submits, approves and posts it in Sales).
| Field | Where | Required | Notes |
|---|---|---|---|
enrolment_id | path | yes | |
party | body (string/null) | Customer code of who pays (default: the learner's payer) | |
unit_price | body (string/null) | Default: the fee item's price |
POST /api/lms/enrolments/{enrolment_id}/withdraw
Withdraw an active enrolment (a completed course stays completed).
| Field | Where | Required | Notes |
|---|---|---|---|
enrolment_id | path | yes |
POST /api/lms/invitations
E-mail a sign-in link: a learner joins the course (under 18: only after the guardian's consent); a guardian gets a read-only view of their learners.
| Field | Where | Required | Notes |
|---|---|---|---|
person_id | body (string) | yes | A learner (with course_id) or a guardian (no course) |
course_id | body (string/null) | ||
cohort_id | body (string/null) |
GET /api/lms/learners
Learners (admins: all with e-mail; instructors: names of learners in their courses).
| Field | Where | Required | Notes |
|---|---|---|---|
q | query |
POST /api/lms/learners
Add a learner (the minimum: name; e-mail for sign-in; birth year only to know a minor).
| Field | Where | Required | Notes |
|---|---|---|---|
full_name | body (string) | yes | |
email | body (string/null) | ||
phone | body (string/null) | ||
birth_year | body (integer/null) | Year only, to know whether the learner is under 18 | |
is_minor | body (boolean) | ||
language | body (string) | ||
payer | body (string/null) | Customer code of who pays the fees (optional) |
GET /api/lms/learners/{learner_id}
One learner: profile, guardians, consents and courses (instructors see only their courses, no contacts).
| Field | Where | Required | Notes |
|---|---|---|---|
learner_id | path | yes |
PATCH /api/lms/learners/{learner_id}
Change a learner's details.
| Field | Where | Required | Notes |
|---|---|---|---|
learner_id | path | yes | |
full_name | body (string/null) | ||
email | body (string/null) | ||
phone | body (string/null) | ||
birth_year | body (integer/null) | ||
is_minor | body (boolean/null) | ||
language | body (string/null) | ||
status | body (string/null) | ||
payer | body (string/null) |
POST /api/lms/learners/{learner_id}/erase
Erase a learner's personal data on request (name, contacts, written answers; a public check that printed the full name is withdrawn).
| Field | Where | Required | Notes |
|---|---|---|---|
learner_id | path | yes | |
confirm_name | body (string) | yes | The learner's full name, typed to confirm |
GET /api/lms/learners/{learner_id}/export
Everything held on one learner, as one file (privacy request).
| Field | Where | Required | Notes |
|---|---|---|---|
learner_id | path | yes |
POST /api/lms/learners/{learner_id}/guardians
Link a guardian to a learner (read-only view of the learner's courses and certificates when they sign in).
| Field | Where | Required | Notes |
|---|---|---|---|
learner_id | path | yes | |
full_name | body (string) | yes | |
email | body (string/null) | ||
phone | body (string/null) |
DELETE /api/lms/lessons/{lesson_id}
Remove a lesson nobody has done yet (otherwise mark it not required).
| Field | Where | Required | Notes |
|---|---|---|---|
lesson_id | path | yes |
PATCH /api/lms/lessons/{lesson_id}
Change a lesson.
| Field | Where | Required | Notes |
|---|---|---|---|
lesson_id | path | yes | |
title | body (string/null) | ||
kind | body (string/null) | ||
body | body (string/null) | ||
link_url | body (string/null) | ||
required | body (boolean/null) |
POST /api/lms/people/{person_id}/consents
Record a consent answer (who accepted what, which text version, now).
| Field | Where | Required | Notes |
|---|---|---|---|
person_id | path | yes | |
purpose | body (string) | yes | |
accepted | body (boolean) | yes | |
given_by | body (string) | yes | |
given_by_name | body (string) | yes | |
text_version | body (string) |
GET /api/lms/sessions/{session_id}
One session with its learners and their attendance.
| Field | Where | Required | Notes |
|---|---|---|---|
session_id | path | yes |
POST /api/lms/sessions/{session_id}/attendance
Mark attendance (present, absent, late, excused); optionally mark the session held or cancelled.
| Field | Where | Required | Notes |
|---|---|---|---|
session_id | path | yes | |
marks | body (array) | ||
status | body (string/null) |
GET /api/lms/staff
Members and their Learning parts (admin, instructor).
POST /api/lms/staff
Give or take a Learning part (admin or instructor) for a member.
| Field | Where | Required | Notes |
|---|---|---|---|
user_id | body (string) | yes | A member of the company |
part | body (string) | yes | |
on | body (boolean) | true = give the part, false = take it away |
learning-me
GET /api/lms/me
My learning here: my courses and progress, announcements, upcoming sessions, courses I may join; for a guardian, the wards.
GET /api/lms/me/assessments/{assessment_id}
A quiz to take: its questions (never the answers) and attempts left.
| Field | Where | Required | Notes |
|---|---|---|---|
assessment_id | path | yes |
POST /api/lms/me/assessments/{assessment_id}/attempts
Submit my answers: scored at once against the pass mark; uses one attempt.
| Field | Where | Required | Notes |
|---|---|---|---|
assessment_id | path | yes | |
answers | body (object) | {question id: chosen index or written answer} |
GET /api/lms/me/certificates/{certificate_id}
My certificate (or my ward's) with its verification link and QR code.
| Field | Where | Required | Notes |
|---|---|---|---|
certificate_id | path | yes |
GET /api/lms/me/courses/{course_id}
One of my courses: lessons (done or not), quizzes with attempts left and best score, announcements, certificate.
| Field | Where | Required | Notes |
|---|---|---|---|
course_id | path | yes |
POST /api/lms/me/courses/{course_id}/join
Join a course that allows self-enrolment (adults only).
| Field | Where | Required | Notes |
|---|---|---|---|
course_id | path | yes | |
adult | body (boolean) | yes | I am 18 or older |
POST /api/lms/me/invitations/accept
Accept a course invitation link (only with the e-mail address it was sent to).
| Field | Where | Required | Notes |
|---|---|---|---|
token | body (string) | yes |
POST /api/lms/me/lessons/{lesson_id}/done
Mark a lesson as done.
| Field | Where | Required | Notes |
|---|---|---|---|
lesson_id | path | yes |
GET /api/lms/me/places
The schools / academies where I am a learner or guardian.
lookups
GET /api/lookups/banks
Banks by name (or SWIFT/BIC), optionally in one country first; includes banks your company added.
| Field | Where | Required | Notes |
|---|---|---|---|
q | query | ||
country | query | ||
limit | query |
POST /api/lookups/banks
Add a bank missing from the list ('other'); refused when it is already there under the same name or SWIFT.
| Field | Where | Required | Notes |
|---|---|---|---|
country | body (string) | yes | |
name | body (string) | yes | |
swift | body (string) |
GET /api/lookups/countries
Countries by name (English / Urdu / Arabic), ISO code or dial code: flag, dial code, currency, languages.
| Field | Where | Required | Notes |
|---|---|---|---|
q | query | ||
limit | query |
GET /api/lookups/currencies
Currencies by code, name, symbol or country ('yen', 'JPY', 'Japan', 'جاپان' all find Japanese Yen): symbol, minor units.
| Field | Where | Required | Notes |
|---|---|---|---|
q | query | ||
limit | query |
GET /api/lookups/places
A place name to coordinates (OpenStreetMap; looked up when you press Enter, cached; only the place name goes out).
| Field | Where | Required | Notes |
|---|---|---|---|
q | query | yes |
GET /api/lookups/sources
Where every list and outside service comes from: licence, limits, attribution, last success.
GET /api/lookups/weather
Weather now (temperature, humidity, wind) and the next days at a coordinate; cached one hour; 'unavailable' when the service does not answer.
| Field | Where | Required | Notes |
|---|---|---|---|
lat | query | yes | |
lon | query | yes |
members
GET /api/members
Everyone in this company with their role.
POST /api/members
Add a person to this company with a role (owner or CFO only; only an owner can make another owner).
| Field | Where | Required | Notes |
|---|---|---|---|
email | body (string) | yes | |
full_name | body (string) | yes | |
role | body (string) | yes |
POST /api/members/{user_id}/invite
A fresh one-time invite link for a member who has not joined yet (owner or CFO): emailed to them and returned so it can also be shared another way.
| Field | Where | Required | Notes |
|---|---|---|---|
user_id | path | yes |
GET /api/members/{user_id}/permissions
A member's extra permissions on top of their role (e.g.
| Field | Where | Required | Notes |
|---|---|---|---|
user_id | path | yes |
PUT /api/members/{user_id}/permissions
Set a member's extra permissions (owner or CFO).
| Field | Where | Required | Notes |
|---|---|---|---|
user_id | path | yes | |
permissions | body (array) | yes | Extra capabilities on top of the role: customize = rename labels |
notifications
GET /api/notifications
Your notifications, newest first.
| Field | Where | Required | Notes |
|---|---|---|---|
category | query | ||
unread_only | query | ||
limit | query |
POST /api/notifications/read
Mark your notifications read — the given ids, or all of them when ids is left out.
| Field | Where | Required | Notes |
|---|---|---|---|
ids | body (array/null) | Notification ids; leave out to mark ALL your notifications read |
GET /api/notifications/summary
How many unread bell notices and open to-dos you have (for badges).
POST /api/notifications/{notification_id}/read
Mark one of your notifications read.
| Field | Where | Required | Notes |
|---|---|---|---|
notification_id | path | yes |
organisation
GET /api/branches
Every branch of this company (closed ones too unless include_closed=false).
| Field | Where | Required | Notes |
|---|---|---|---|
include_closed | query |
POST /api/branches
Add a branch (owner, CFO or accountant; within the plan's limit).
| Field | Where | Required | Notes |
|---|---|---|---|
code | body (string) | yes | Short code, e.g. |
name | body (string) | yes |
GET /api/branches/{item_id}
One branch.
| Field | Where | Required | Notes |
|---|---|---|---|
item_id | path | yes |
POST /api/branches/{item_id}
Rename, close (active=false) or reopen a branch.
| Field | Where | Required | Notes |
|---|---|---|---|
item_id | path | yes | |
name | body (string/null) | ||
active | body (boolean/null) | false closes it: no new postings; history stays |
GET /api/cost-centres
Every cost centre of this company (closed ones too unless include_closed=false).
| Field | Where | Required | Notes |
|---|---|---|---|
include_closed | query |
POST /api/cost-centres
Add a cost centre (owner, CFO or accountant; within the plan's limit).
| Field | Where | Required | Notes |
|---|---|---|---|
code | body (string) | yes | Short code, e.g. |
name | body (string) | yes |
GET /api/cost-centres/{item_id}
One cost centre.
| Field | Where | Required | Notes |
|---|---|---|---|
item_id | path | yes |
POST /api/cost-centres/{item_id}
Rename, close (active=false) or reopen a cost centre.
| Field | Where | Required | Notes |
|---|---|---|---|
item_id | path | yes | |
name | body (string/null) | ||
active | body (boolean/null) | false closes it: no new postings; history stays |
GET /api/projects
Every project of this company (closed ones too unless include_closed=false).
| Field | Where | Required | Notes |
|---|---|---|---|
include_closed | query |
POST /api/projects
Add a project (owner, CFO or accountant; within the plan's limit).
| Field | Where | Required | Notes |
|---|---|---|---|
code | body (string) | yes | Short code, e.g. |
name | body (string) | yes | |
branch | body (string/null) | Code of the branch the project runs under | |
start_date | body (string/null) | ||
end_date | body (string/null) |
GET /api/projects/{item_id}
One project.
| Field | Where | Required | Notes |
|---|---|---|---|
item_id | path | yes |
POST /api/projects/{item_id}
Rename, close (active=false) or reopen a project, or change its branch and dates.
| Field | Where | Required | Notes |
|---|---|---|---|
item_id | path | yes | |
name | body (string/null) | ||
active | body (boolean/null) | false closes it: no new postings; history stays | |
branch | body (string/null) | Branch code; send "" to detach from a branch | |
start_date | body (string/null) | ||
end_date | body (string/null) |
periods
GET /api/periods
Accounting periods and whether each is open or locked.
POST /api/periods
Open an accounting period (owner, CFO or accountant).
| Field | Where | Required | Notes |
|---|---|---|---|
start_date | body (string) | yes | |
end_date | body (string) | yes |
POST /api/periods/{start_date}/lock
Lock the period starting on this date (owner or CFO).
| Field | Where | Required | Notes |
|---|---|---|---|
start_date | path | yes |
plans
GET /api/plans
Every plan and what it includes (users, branches, projects, cost centres, modules).
public
GET /api/public/verify/{code}
Public check of a printed document's verification code: type, number, issuer, date, total (if the issuer allows), status and whether the stored facts still match their hash chain.
| Field | Where | Required | Notes |
|---|---|---|---|
code | path | yes |
records
GET /api/attachments/{attachment_id}
One file's details and read text.
| Field | Where | Required | Notes |
|---|---|---|---|
attachment_id | path | yes |
GET /api/attachments/{attachment_id}/file
The file itself (only for people who may open its record).
| Field | Where | Required | Notes |
|---|---|---|---|
attachment_id | path | yes |
PUT /api/attachments/{attachment_id}/ocr-text
Correct what the machine read (owner, CFO, accountant); the machine-read text is kept as it was.
| Field | Where | Required | Notes |
|---|---|---|---|
attachment_id | path | yes | |
text | body (string) | yes |
POST /api/attachments/{attachment_id}/remove
Remove a file (soft: it stays on record as removed, with who, when and why).
| Field | Where | Required | Notes |
|---|---|---|---|
attachment_id | path | yes | |
reason | body (string) | yes |
GET /api/records/{ref_type}/{ref_id}/attachments
Files of a record, with the reading status (pending / done / failed / skipped), the read text and removed files (on record).
| Field | Where | Required | Notes |
|---|---|---|---|
ref_type | path | yes | |
ref_id | path | yes |
POST /api/records/{ref_type}/{ref_id}/attachments
Attach a file (PDF, photo, Excel/CSV, Word, text) to a record.
| Field | Where | Required | Notes |
|---|---|---|---|
ref_type | path | yes | |
ref_id | path | yes | |
filename | body (string) | yes | With its extension: pdf, png, jpg, webp, gif, tif, xlsx, xls, csv, docx, doc, txt |
content_base64 | body (string) | yes |
GET /api/records/{ref_type}/{ref_id}/notes
Description and remarks of a record (any transaction type).
| Field | Where | Required | Notes |
|---|---|---|---|
ref_type | path | yes | |
ref_id | path | yes |
PUT /api/records/{ref_type}/{ref_id}/notes
Write the description / remarks of a record (allowed after posting too; every change is kept in its history).
| Field | Where | Required | Notes |
|---|---|---|---|
ref_type | path | yes | |
ref_id | path | yes | |
description | body (string/null) | ||
remarks | body (string/null) | Free remarks, e.g. |
report-studio
GET /api/report-studio/datasets
What your role may build reports from: datasets, their fields (type, allowed totals, date groupings).
POST /api/report-studio/preview
Run a report definition now without saving it (the builder's live preview).
| Field | Where | Required | Notes |
|---|---|---|---|
dataset | body (string) | yes | journal_lines, documents, document_lines, parties, items, stock_balances, einvoices |
columns | body (array) | yes | |
filters | body (array) | ||
sort | body (array) | ||
limit | body (integer) | ||
period | body (object/null) | ||
start | body (string/null) | Override the period: first date | |
end | body (string/null) | Override the period: last date | |
preview_limit | body (integer) | How many rows to show in the preview |
GET /api/report-studio/reports
Your saved reports and the ones shared with your role.
POST /api/report-studio/reports
Save a report definition under a name (optionally shared with roles — owner/CFO only).
| Field | Where | Required | Notes |
|---|---|---|---|
dataset | body (string) | yes | journal_lines, documents, document_lines, parties, items, stock_balances, einvoices |
columns | body (array) | yes | |
filters | body (array) | ||
sort | body (array) | ||
limit | body (integer) | ||
period | body (object/null) | ||
name | body (string) | yes | |
description | body (string) | ||
shared_roles | body (array) | Roles that may open (not change) it — owner/CFO only |
DELETE /api/report-studio/reports/{report_id}
Delete one of your own saved reports.
| Field | Where | Required | Notes |
|---|---|---|---|
report_id | path | yes |
GET /api/report-studio/reports/{report_id}
One saved report with its definition.
| Field | Where | Required | Notes |
|---|---|---|---|
report_id | path | yes |
PUT /api/report-studio/reports/{report_id}
Replace one of your own saved reports.
| Field | Where | Required | Notes |
|---|---|---|---|
report_id | path | yes | |
dataset | body (string) | yes | journal_lines, documents, document_lines, parties, items, stock_balances, einvoices |
columns | body (array) | yes | |
filters | body (array) | ||
sort | body (array) | ||
limit | body (integer) | ||
period | body (object/null) | ||
name | body (string) | yes | |
description | body (string) | ||
shared_roles | body (array) | Roles that may open (not change) it — owner/CFO only |
GET /api/report-studio/reports/{report_id}/export
A saved report as JSON, printable HTML, PDF, Excel or CSV (up to its row limit).
| Field | Where | Required | Notes |
|---|---|---|---|
report_id | path | yes | |
format | query | ||
start | query | ||
end | query |
GET /api/report-studio/reports/{report_id}/run
Run a saved report with YOUR role's view of the data (start / end override its period).
| Field | Where | Required | Notes |
|---|---|---|---|
report_id | path | yes | |
start | query | ||
end | query | ||
limit | query |
reports
GET /api/reports
The reports your role may open and export, with their parameters and formats.
GET /api/reports/aging/{kind}
Who owes us (receivable) / whom we owe (payable), by how overdue, in base currency.
| Field | Where | Required | Notes |
|---|---|---|---|
kind | path | yes | |
as_of | query |
GET /api/reports/balance-sheet
Assets, liabilities, equity and accumulated profit as of a date (default today).
| Field | Where | Required | Notes |
|---|---|---|---|
as_of | query |
GET /api/reports/bank-reconciliation/{code}
Bank reconciliation as of a date (default today): statement balance, book balance, uncleared ledger lines, unmatched statement lines and the difference (0 when reconciled).
| Field | Where | Required | Notes |
|---|---|---|---|
code | path | yes | |
as_of | query |
GET /api/reports/fx-summary
Realised and unrealised exchange results posted between two dates (base currency; + = gain).
| Field | Where | Required | Notes |
|---|---|---|---|
start | query | yes | |
end | query | yes |
GET /api/reports/grni
Goods received not invoiced as of a date (default today): each open goods-received line, the total, the GRNI control balance and the difference (always 0).
| Field | Where | Required | Notes |
|---|---|---|---|
as_of | query |
GET /api/reports/party-statement/{party}
A customer's or vendor's statement for a period: opening, each posted document, running balance, closing.
| Field | Where | Required | Notes |
|---|---|---|---|
party | path | yes | |
start | query | yes | |
end | query | yes | |
kind | query |
GET /api/reports/profit-and-loss
Income, expenses and net profit between two dates (inclusive).
| Field | Where | Required | Notes |
|---|---|---|---|
start | query | yes | |
end | query | yes | |
branch | query | ||
project | query | ||
cost_centre | query |
GET /api/reports/profit-and-loss-by
Net profit per branch, project or cost centre between two dates, plus an "unassigned" row; the rows add up to the P&L.
| Field | Where | Required | Notes |
|---|---|---|---|
start | query | yes | |
end | query | yes | |
dimension | query | yes |
GET /api/reports/reorder
Stock items at or below their reorder level, with the quantity to order.
| Field | Where | Required | Notes |
|---|---|---|---|
warehouse | query |
GET /api/reports/stock-ledger/{item}
Every movement of one item between two dates: opening, each move (source number, warehouse, in/out, value, running quantity and value), closing.
| Field | Where | Required | Notes |
|---|---|---|---|
item | path | yes | |
start | query | yes | |
end | query | yes | |
warehouse | query |
GET /api/reports/stock-valuation
Quantity, value and unit cost per item × warehouse as of a date (default today), the total and — for the whole company — the inventory control balance and the difference (always 0).
| Field | Where | Required | Notes |
|---|---|---|---|
as_of | query | ||
warehouse | query |
GET /api/reports/trial-balance
Trial balance as of a date (default today).
| Field | Where | Required | Notes |
|---|---|---|---|
as_of | query | ||
branch | query | ||
project | query | ||
cost_centre | query |
GET /api/reports/{name}/export
Any report as JSON (every row with its drill-down link to the source entry/document), HTML (printable, branded with the company name), PDF, Excel (XLSX) or CSV.
| Field | Where | Required | Notes |
|---|---|---|---|
name | path | yes | |
format | query | ||
as_of | query | ||
start | query | ||
end | query | ||
dimension | query | ||
account | query | Account code (account-ledger) | |
party | query | Customer/vendor code (statement) | |
warehouse | query | Warehouse code (stock-valuation) | |
bank | query | Bank account code (bank-reconciliation) | |
pack | query | Tax pack code, e.g. | |
branch | query | ||
project | query | ||
cost_centre | query |
search
GET /api/search
Find accounts, customers/vendors, items, documents (number, party, reference), journal entries (number, memo), members, branches, projects and cost centres — typo-tolerant, Urdu/Arabic aware, only what your role may see.
| Field | Where | Required | Notes |
|---|---|---|---|
q | query | yes | |
limit | query |
settings
GET /api/settings/approvals
This company's approval settings: may a SOLE approver approve their own work with a written review (audited), and do eligible approvers also get an e-mail (the bell and To-Do always).
PUT /api/settings/approvals
Change the approval settings (owner or CFO).
| Field | Where | Required | Notes |
|---|---|---|---|
sole_approver_self_approval | body (boolean/null) | ||
email_approvers | body (boolean/null) |
DELETE /api/settings/approvals/limits
The role may no longer approve this document type (owner or CFO; audited; never the last unlimited approver).
| Field | Where | Required | Notes |
|---|---|---|---|
doc_type | query | yes | |
role | query | yes |
PUT /api/settings/approvals/limits
Set what a role may approve for a document type (max_amount null = no limit).
| Field | Where | Required | Notes |
|---|---|---|---|
doc_type | body (string) | yes | |
role | body (string) | yes | |
max_amount | body (number/string/null) |
supply_chain
GET /api/supply-chain/categories
The item categories in use, with how many items and critical items each has.
GET /api/supply-chain/critical-items
Early warnings: for each critical item, days of stock left (stock ÷ average daily use from our own issues) against days until the next arrival (open purchase orders), with status stockout / late / gap / watch / ok and a reorder suggestion.
| Field | Where | Required | Notes |
|---|---|---|---|
window_days | query | ||
mine | query | ||
include_all | query |
POST /api/supply-chain/critical-items/draft-requisition
Put the reorder suggestions of the chosen items into ONE DRAFT purchase requisition (nothing is ordered; a person submits it).
| Field | Where | Required | Notes |
|---|---|---|---|
items | body (array) | yes | Item codes from the reorder suggestions |
needed_by | body (string/null) | ||
warehouse | body (string/null) |
GET /api/supply-chain/feeds
The feeds this company reads, with when each was last read and how it went.
POST /api/supply-chain/feeds
Add an RSS / Atom feed (https, on a trusted site) to read: trade, chemicals, shipping, ports, news or prices (owner or CFO).
| Field | Where | Required | Notes |
|---|---|---|---|
url | body (string) | yes | https address of an RSS or Atom feed on a trusted site |
title | body (string) | ||
topic | body (string) |
PATCH /api/supply-chain/feeds/{feed_id}
Rename a feed, change its topic, or switch it off / on (owner or CFO).
| Field | Where | Required | Notes |
|---|---|---|---|
feed_id | path | yes | |
title | body (string/null) | ||
topic | body (string/null) | ||
active | body (boolean/null) |
POST /api/supply-chain/feeds/{feed_id}/read-now
Read one feed now (owner or CFO; the company's signals must be switched on).
| Field | Where | Required | Notes |
|---|---|---|---|
feed_id | path | yes |
GET /api/supply-chain/hub-cards
Supply chain cards for my day: my critical items at risk, requisitions waiting for my decision, supplier papers expiring, and this week's top signals (not verified).
GET /api/supply-chain/items
Items with their supply settings: category, critical, single source, lead time, cover days, buyer and number of approved sources.
| Field | Where | Required | Notes |
|---|---|---|---|
critical | query | ||
category | query | ||
q | query |
GET /api/supply-chain/items/{code}
One item's supply settings, its approved sources (primary and alternates with channel) and sourcing risks (single source ...).
| Field | Where | Required | Notes |
|---|---|---|---|
code | path | yes |
PATCH /api/supply-chain/items/{code}
Mark an item critical or single-source, set its category, planning lead time, cover days and the buyer who watches it.
| Field | Where | Required | Notes |
|---|---|---|---|
code | path | yes | |
category | body (string/null) | The company's own category words: Valves, Drilling chemicals ... | |
critical | body (boolean/null) | ||
single_source | body (boolean/null) | ||
lead_time_days | body (integer/null) | Planning lead time; empty = use what our deliveries show | |
cover_days | body (integer/null) | Warn when days of stock left falls below this | |
buyer_id | body (string/null) | The member who watches this item |
POST /api/supply-chain/items/{code}/sources
Approve a supplier as the primary source or an approved alternate for an item, with its channel (OEM, distributor, agent ...).
| Field | Where | Required | Notes |
|---|---|---|---|
code | path | yes | |
supplier | body (string) | yes | Supplier (vendor) code |
role | body (string) | ||
channel | body (string) | ||
note | body (string) |
POST /api/supply-chain/items/{code}/sources/{supplier}/remove
The supplier is no longer an approved source of the item (kept on record as inactive).
| Field | Where | Required | Notes |
|---|---|---|---|
code | path | yes | |
supplier | path | yes |
GET /api/supply-chain/papers/expiring
Supplier papers already expired or expiring within the given days, soonest first.
| Field | Where | Required | Notes |
|---|---|---|---|
within_days | query |
GET /api/supply-chain/requisitions
Purchase requisitions, newest first; mine=true: the ones I made; waiting_me=true: submitted ones someone else made (for approvers).
| Field | Where | Required | Notes |
|---|---|---|---|
status | query | ||
mine | query | ||
waiting_me | query |
POST /api/supply-chain/requisitions
Prepare a DRAFT purchase requisition (items, quantities, estimated prices, needed-by date, warehouse, reason).
| Field | Where | Required | Notes |
|---|---|---|---|
lines | body (array) | yes | |
needed_by | body (string/null) | ||
warehouse | body (string/null) | ||
reason | body (string) |
GET /api/supply-chain/requisitions/{requisition_id}
One requisition with its lines, estimated value, status, who made / decided it, its history and its purchase order.
| Field | Where | Required | Notes |
|---|---|---|---|
requisition_id | path | yes |
PUT /api/supply-chain/requisitions/{requisition_id}
Change a draft requisition (its maker only).
| Field | Where | Required | Notes |
|---|---|---|---|
requisition_id | path | yes | |
lines | body (array) | yes | |
needed_by | body (string/null) | ||
warehouse | body (string/null) | ||
reason | body (string) |
POST /api/supply-chain/requisitions/{requisition_id}/approve
Approve a submitted requisition: never by its maker; the role and limit come from the company's approval rules.
| Field | Where | Required | Notes |
|---|---|---|---|
requisition_id | path | yes | |
note | body (string) |
POST /api/supply-chain/requisitions/{requisition_id}/cancel
Cancel a requisition that is not ordered yet (its maker, the owner or the CFO).
| Field | Where | Required | Notes |
|---|---|---|---|
requisition_id | path | yes | |
reason | body (string) |
GET /api/supply-chain/requisitions/{requisition_id}/offers
Offers side by side: landed cost (price + freight + duty + other, in base currency), lines covered, lead time, validity, and the supplier's on-time and return record from our own deliveries.
| Field | Where | Required | Notes |
|---|---|---|---|
requisition_id | path | yes |
POST /api/supply-chain/requisitions/{requisition_id}/offers
Enter a supplier's offer against a requisition: unit prices, currency and exchange rate, freight, duty, other costs, lead time, when we asked and when it came (for the supplier's response time).
| Field | Where | Required | Notes |
|---|---|---|---|
requisition_id | path | yes | |
supplier | body (string) | yes | |
lines | body (array) | yes | |
currency | body (string/null) | ||
fx_rate | body (number/string) | Offer currency → base currency | |
freight | body (number/string) | ||
duty | body (number/string) | ||
other_costs | body (number/string) | ||
lead_time_days | body (integer/null) | ||
requested_on | body (string/null) | ||
received_on | body (string/null) | ||
valid_until | body (string/null) | ||
note | body (string) |
DELETE /api/supply-chain/requisitions/{requisition_id}/offers/{offer_id}
Remove an offer typed in by mistake (not after the requisition is ordered).
| Field | Where | Required | Notes |
|---|---|---|---|
requisition_id | path | yes | |
offer_id | path | yes |
POST /api/supply-chain/requisitions/{requisition_id}/offers/{offer_id}/choose
Choose the offer the purchase order will use (one per requisition).
| Field | Where | Required | Notes |
|---|---|---|---|
requisition_id | path | yes | |
offer_id | path | yes |
POST /api/supply-chain/requisitions/{requisition_id}/purchase-order
From an APPROVED requisition and its chosen offer, prepare a DRAFT purchase order (it then goes through the normal purchase-order approval).
| Field | Where | Required | Notes |
|---|---|---|---|
requisition_id | path | yes | |
doc_date | body (string/null) |
POST /api/supply-chain/requisitions/{requisition_id}/reject
Send a submitted requisition back to its maker with the reason (never by its maker).
| Field | Where | Required | Notes |
|---|---|---|---|
requisition_id | path | yes | |
reason | body (string) | yes |
POST /api/supply-chain/requisitions/{requisition_id}/reopen
Turn a sent-back requisition into a draft again so its maker can fix it.
| Field | Where | Required | Notes |
|---|---|---|---|
requisition_id | path | yes |
POST /api/supply-chain/requisitions/{requisition_id}/submit
Send a draft requisition for approval (its maker); it gets its PR number.
| Field | Where | Required | Notes |
|---|---|---|---|
requisition_id | path | yes |
GET /api/supply-chain/requisitions/{requisition_id}/supplier-suggestions
For each line: the approved sources of the item and the suppliers who delivered it in our own orders (last price, orders, on-time %).
| Field | Where | Required | Notes |
|---|---|---|---|
requisition_id | path | yes |
GET /api/supply-chain/scorecards
Supplier scorecards from our own orders, goods receipts, debit notes and offers: on-time %, promised vs actual lead time, return rate, price trend, response time — per supplier or per item category (default: the last 365 days).
| Field | Where | Required | Notes |
|---|---|---|---|
by | query | ||
from | query | ||
to | query |
GET /api/supply-chain/scorecards/{code}
One supplier's scorecard with its price history per item and the deliveries behind the numbers.
| Field | Where | Required | Notes |
|---|---|---|---|
code | path | yes | |
from | query | ||
to | query |
GET /api/supply-chain/signal-keywords
The company's own words that make a feed item relevant, and what each points at (category, supplier, region, item).
POST /api/supply-chain/signal-keywords
Add a keyword with its weight (1-5) and what it points at; recent signals are scored again (owner, CFO or purchase).
| Field | Where | Required | Notes |
|---|---|---|---|
keyword | body (string) | yes | |
target_type | body (string) | ||
target | body (string) | The category name, supplier code, region or item code it points at | |
weight | body (integer) |
GET /api/supply-chain/signal-keywords/suggestions
Words the company already uses (item categories, supplier names, regions served), ready to add as keywords.
DELETE /api/supply-chain/signal-keywords/{keyword_id}
Remove a keyword; recent signals are scored again (owner, CFO or purchase).
| Field | Where | Required | Notes |
|---|---|---|---|
keyword_id | path | yes |
GET /api/supply-chain/signal-settings
Whether this company's feeds are read, its trusted sites and the minimum relevance shown.
PATCH /api/supply-chain/signal-settings
Switch the feed reader on or off for this company, set the trusted sites and the minimum relevance (owner or CFO).
| Field | Where | Required | Notes |
|---|---|---|---|
enabled | body (boolean/null) | Read this company's feeds in the background | |
allowed_hosts | body (array/null) | Trusted sites: www.example.com or *.example.com | |
min_score | body (integer/null) |
GET /api/supply-chain/signals
Signals for your items: news / trade / shipping feed items matched to the company's keywords, most relevant first, each with a link to its source.
| Field | Where | Required | Notes |
|---|---|---|---|
days | query | ||
min_score | query | ||
target_type | query | ||
target | query | ||
include_dismissed | query |
POST /api/supply-chain/signals/{signal_id}/dismiss
Hide a signal that is not useful (for everyone in the company).
| Field | Where | Required | Notes |
|---|---|---|---|
signal_id | path | yes |
GET /api/supply-chain/suppliers
Suppliers (vendors) with their supply profile: type (OEM, authorised distributor, local agent ...), regions and countries served, qualification, and how many of their papers are expired or expiring.
| Field | Where | Required | Notes |
|---|---|---|---|
supplier_type | query | ||
qualification | query | ||
country | query | ||
region | query | ||
q | query |
GET /api/supply-chain/suppliers/{code}
One supplier's supply profile, its papers (certificates with expiry state) and the items it is an approved source for.
| Field | Where | Required | Notes |
|---|---|---|---|
code | path | yes |
PATCH /api/supply-chain/suppliers/{code}
Set a supplier's type, regions, countries, qualification status and review date (owner, CFO, accountant, clerk, purchase).
| Field | Where | Required | Notes |
|---|---|---|---|
code | path | yes | |
supplier_type | body (string/null) | ||
regions | body (array/null) | Regions served, in the company's own words (Gulf, Sindh ...) | |
countries | body (array/null) | Two-letter country codes served (PK, SA, AE ...) | |
qualification | body (string/null) | ||
qualified_on | body (string/null) | ||
review_due | body (string/null) | When the qualification must be reviewed again | |
notes | body (string/null) |
POST /api/supply-chain/suppliers/{code}/papers
Record a supplier paper (quality certificate, registration, local-content certificate, authorisation letter ...) with its expiry.
| Field | Where | Required | Notes |
|---|---|---|---|
code | path | yes | |
kind | body (string) | yes | |
title | body (string) | yes | e.g. |
reference | body (string) | ||
issued_on | body (string/null) | ||
expires_on | body (string/null) |
POST /api/supply-chain/suppliers/{code}/papers/{paper_id}/withdraw
Withdraw a supplier paper that was replaced or wrong (it stays on record as withdrawn; nothing is deleted).
| Field | Where | Required | Notes |
|---|---|---|---|
code | path | yes | |
paper_id | path | yes |
system
GET /api/health
Liveness + database check (no sign-in needed).
GET /api/tools
Every capability of the API as a tool (name, description, input schema, writes → preview + confirm).
GET /api/version
The build id of the live screens.
tax
GET /api/tax/einvoices
E-invoices of the company, newest first.
| Field | Where | Required | Notes |
|---|---|---|---|
status | query | draft, confirmed, submitted, accepted, rejected, cancelled | |
document_id | query | ||
limit | query |
POST /api/tax/einvoices
Prepare the government e-invoice DRAFT of a posted sales invoice / credit note.
| Field | Where | Required | Notes |
|---|---|---|---|
document_id | body (string) | yes | The posted sales invoice or credit note |
pack_code | body (string/null) |
GET /api/tax/einvoices/ready
Posted sales invoices and credit notes that have no e-invoice yet — the ones a person can prepare next.
| Field | Where | Required | Notes |
|---|---|---|---|
pack_code | query | ||
limit | query |
GET /api/tax/einvoices/{einvoice_id}
One e-invoice: summary (buyer, totals, QR text, hash), open issues and its history.
| Field | Where | Required | Notes |
|---|---|---|---|
einvoice_id | path | yes | |
include_payload | query |
POST /api/tax/einvoices/{einvoice_id}/cancel
Withdraw a draft or confirmed (not yet submitted) e-invoice, with the reason.
| Field | Where | Required | Notes |
|---|---|---|---|
einvoice_id | path | yes | |
reason | body (string) | yes |
POST /api/tax/einvoices/{einvoice_id}/confirm
A PERSON confirms the e-invoice they checked (content_hash as shown).
| Field | Where | Required | Notes |
|---|---|---|---|
einvoice_id | path | yes | |
content_hash | body (string) | yes | The hash shown on the draft (summary.content_hash / data_hash): proof you saw this content |
statement | body (string) | yes | Your own words that you checked it, e.g. |
GET /api/tax/einvoices/{einvoice_id}/file
The e-invoice as a file (FBR JSON or ZATCA UBL XML) to check or to upload in the authority's portal.
| Field | Where | Required | Notes |
|---|---|---|---|
einvoice_id | path | yes |
POST /api/tax/einvoices/{einvoice_id}/refresh
Rebuild a DRAFT after fixing the customer / item profile or the pack details.
| Field | Where | Required | Notes |
|---|---|---|---|
einvoice_id | path | yes |
POST /api/tax/einvoices/{einvoice_id}/result
Write down the authority's answer (accepted + reference, or rejected + why), e.g.
| Field | Where | Required | Notes |
|---|---|---|---|
einvoice_id | path | yes | |
accepted | body (boolean) | yes | |
reference | body (string) | The reference the authority gave (needed when accepted) | |
message | body (string) |
POST /api/tax/einvoices/{einvoice_id}/submit
Send a CONFIRMED e-invoice to the tax authority through the company's connection.
| Field | Where | Required | Notes |
|---|---|---|---|
einvoice_id | path | yes |
GET /api/tax/items/{item_code}/profile
An item's tax profile: HS code, unit, sale type, retail price.
| Field | Where | Required | Notes |
|---|---|---|---|
item_code | path | yes |
PUT /api/tax/items/{item_code}/profile
Set an item's tax profile (only the fields you send change).
| Field | Where | Required | Notes |
|---|---|---|---|
item_code | path | yes | |
hs_code | body (string/null) | Pakistan: HS code like 0101.2100 | |
uom | body (string/null) | Pakistan: unit exactly as in FBR's list; Saudi: UN/ECE code (PCE, KGM …) | |
sale_type | body (string/null) | Pakistan: standard, reduced, exempt, zero, third_schedule, services | |
sro_item_serial_no | body (string/null) | ||
retail_price | body (string/null) | Third-schedule goods: the printed retail price |
GET /api/tax/packs
The country tax packs (Pakistan FBR, Saudi ZATCA) and whether this company has switched each on.
GET /api/tax/packs/{pack_code}
One pack as data: the registration details it needs, its tax rules (with rates), the invoice fields and the return layout.
| Field | Where | Required | Notes |
|---|---|---|---|
pack_code | path | yes |
GET /api/tax/packs/{pack_code}/company
This company's use of a pack: details, tax codes, e-invoice counts and what is still missing (plain sentences).
| Field | Where | Required | Notes |
|---|---|---|---|
pack_code | path | yes |
POST /api/tax/packs/{pack_code}/enable
Switch a tax pack on (owner or CFO): saves the company's registration details and creates the pack's tax codes.
| Field | Where | Required | Notes |
|---|---|---|---|
pack_code | path | yes | |
settings | body (object) | yes | The registration details the pack asks for (see the pack's `settings`): e.g. |
output_account | body (string/null) | Account code for tax payable on sales (default: the one document setup uses) | |
input_account | body (string/null) | Account code for tax recoverable on purchases (default: the one document setup uses) |
PUT /api/tax/packs/{pack_code}/settings
Change the registration details of a switched-on pack (owner or CFO).
| Field | Where | Required | Notes |
|---|---|---|---|
pack_code | path | yes | |
settings | body (object) | yes | ALL the pack's settings again (this replaces them). |
POST /api/tax/packs/{pack_code}/tax-codes
Add a company tax code that follows a pack rule (e.g.
| Field | Where | Required | Notes |
|---|---|---|---|
pack_code | path | yes | |
rule | body (string) | yes | A rule of the pack (e.g. |
code | body (string) | yes | |
name | body (string) | yes | |
rate | body (string/null) | Percent; only for rules whose rate the company sets (reduced, services) | |
reason_code | body (string) | ZATCA exemption reason (VATEX-SA-…) for zero-rated, exempt, out of scope | |
sro_schedule_no | body (string) | FBR: the SRO that gives this rate |
GET /api/tax/parties/{party_code}/profile
A customer's tax profile: registration type and address as the tax authority wants them.
| Field | Where | Required | Notes |
|---|---|---|---|
party_code | path | yes |
PUT /api/tax/parties/{party_code}/profile
Set a customer's tax profile (only the fields you send change).
| Field | Where | Required | Notes |
|---|---|---|---|
party_code | path | yes | |
registration_type | body (string/null) | ||
province | body (string/null) | ||
address | body (string/null) | ||
street | body (string/null) | ||
building_number | body (string/null) | ||
district | body (string/null) | ||
city | body (string/null) | ||
postal_code | body (string/null) | ||
country_code | body (string/null) | ||
crn | body (string/null) | ||
extra_ids | body (object/null) | More tax ids the active tax pack asks for (its party_ids keys), e.g. |
GET /api/tax/returns
Saved tax return snapshots.
POST /api/tax/returns
Save the working paper of a period as a draft snapshot for a person to check.
| Field | Where | Required | Notes |
|---|---|---|---|
pack_code | body (string) | yes | |
start | body (string) | yes | |
end | body (string) | yes |
GET /api/tax/returns/working-paper
The tax return working paper of a period: output and input tax by rule, net payable, and anything not mapped to the pack.
| Field | Where | Required | Notes |
|---|---|---|---|
pack_code | query | yes | |
start | query | yes | |
end | query | yes |
GET /api/tax/returns/{return_id}
One saved tax return snapshot with its figures and history.
| Field | Where | Required | Notes |
|---|---|---|---|
return_id | path | yes |
POST /api/tax/returns/{return_id}/cancel
Withdraw a draft or confirmed return snapshot, with the reason.
| Field | Where | Required | Notes |
|---|---|---|---|
return_id | path | yes | |
reason | body (string) | yes |
POST /api/tax/returns/{return_id}/confirm
A PERSON confirms the figures they checked (content_hash = data_hash shown).
| Field | Where | Required | Notes |
|---|---|---|---|
return_id | path | yes | |
content_hash | body (string) | yes | The hash shown on the draft (summary.content_hash / data_hash): proof you saw this content |
statement | body (string) | yes | Your own words that you checked it, e.g. |
POST /api/tax/returns/{return_id}/filed
Write down that a person filed the confirmed return with the authority, with the authority's reference.
| Field | Where | Required | Notes |
|---|---|---|---|
return_id | path | yes | |
reference | body (string) | yes |
GET /api/tax/tax-codes
All tax codes of the company and which pack rule each follows.
GET /api/tax/withholding-categories
Withholding categories of the company's active tax packs, for deduction lines on receipts and payments (rates are the company's tax adviser's, never ours).
verify
GET /api/verify-settings
Whether the public verification page of this company's printed documents shows the total.
PUT /api/verify-settings
Show or hide the total on the public verification page (owner or CFO).
| Field | Where | Required | Notes |
|---|---|---|---|
show_total | body (boolean) | yes | Show the document total and currency on the public verification page |
POST /api/verify/documents/{doc_id}/revoke
Revoke the public verification code of one printed document, with the reason (owner, CFO or accountant).
| Field | Where | Required | Notes |
|---|---|---|---|
doc_id | path | yes | |
reason | body (string) | yes |
verticals
GET /api/verticals
The industry sections of this company (Learning now; Community, Laboratory, Hospital later) and whether each is on.
PUT /api/verticals/{vertical}
Switch an industry section on or off (company owner only).
| Field | Where | Required | Notes |
|---|---|---|---|
vertical | path | yes | |
enabled | body (boolean) | yes |
work
POST /api/work/milestones/{milestone_id}/finish
Mark a milestone done (all its tasks finished), or reopen it.
| Field | Where | Required | Notes |
|---|---|---|---|
milestone_id | path | yes | |
reopen | body (boolean) |
GET /api/work/projects
Projects as work: people, milestones and task progress (% of tasks done).
| Field | Where | Required | Notes |
|---|---|---|---|
include_closed | query |
GET /api/work/projects/{project_id}
One project: people, milestones (at risk when open tasks outnumber the days left) and progress.
| Field | Where | Required | Notes |
|---|---|---|---|
project_id | path | yes |
POST /api/work/projects/{project_id}/members
Add a member to a project as lead or member, or remove them (project lead or owner / CFO / accountant).
| Field | Where | Required | Notes |
|---|---|---|---|
project_id | path | yes | |
user_id | body (string) | yes | |
part | body (string) | ||
remove | body (boolean) |
POST /api/work/projects/{project_id}/milestones
Add a milestone with an optional due date (project lead or owner / CFO / accountant).
| Field | Where | Required | Notes |
|---|---|---|---|
project_id | path | yes | |
title | body (string) | yes | |
due_date | body (string/null) |
GET /api/work/tasks
Tasks: mine, given by me, my team's (owner / CFO see all; others their projects'), or one project's.
| Field | Where | Required | Notes |
|---|---|---|---|
scope | query | ||
status | query | ||
project_id | query | ||
include_snoozed | query |
POST /api/work/tasks
Give a task to a member: due date, repeat, escalation, priority, project / milestone, link to any record.
| Field | Where | Required | Notes |
|---|---|---|---|
title | body (string) | yes | |
assignee_id | body (string) | yes | |
details | body (string) | ||
due_date | body (string/null) | ||
repeat | body (string) | When done, the next one is created by itself | |
escalate_after_days | body (integer/null) | Still open this many days after the due date -> escalated | |
escalate_to | body (string/null) | Member told on escalation (default: who gave it) | |
priority | body (string) | ||
stage | body (string) | ||
project_id | body (string/null) | ||
milestone_id | body (string/null) | ||
ref_type | body (string/null) | ||
ref_id | body (string/null) | The record the task is about |
GET /api/work/tasks/{task_id}
One task with its plan (repeat, snooze, escalation), project and linked record.
| Field | Where | Required | Notes |
|---|---|---|---|
task_id | path | yes |
POST /api/work/tasks/{task_id}/plan
Change a task you gave: due date, repeat, escalation or priority (a new due date restarts reminders and escalation).
| Field | Where | Required | Notes |
|---|---|---|---|
task_id | path | yes | |
due_date | body (string/null) | ||
repeat | body (string/null) | ||
escalate_after_days | body (integer/null) | ||
escalate_to | body (string/null) | ||
priority | body (string/null) | ||
clear_escalation | body (boolean) |
POST /api/work/tasks/{task_id}/snooze
Snooze your task until a date (it comes back with a notice); until=null ends the snooze.
| Field | Where | Required | Notes |
|---|---|---|---|
task_id | path | yes | |
until | body (string/null) | Hide until this date; null ends the snooze |
POST /api/work/tasks/{task_id}/stage
Move a task on the board: to do, doing or waiting (mark it done to finish it).
| Field | Where | Required | Notes |
|---|---|---|---|
task_id | path | yes | |
stage | body (string) | yes |
workspace
GET /api/ux/actions/{kind}/{ref_id}
The right-click actions I may use on one record (open, copy link, task, note, share, attach, print, history, ask Star).
| Field | Where | Required | Notes |
|---|---|---|---|
kind | path | yes | |
ref_id | path | yes |
PUT /api/ux/company/brand
Owner / CFO: the company's brand colour (buttons, highlights) for everyone in the company.
| Field | Where | Required | Notes |
|---|---|---|---|
brand | body (object/null) | {colour, ink}; words on the brand colour must be 4.5:1; null = standard |
PUT /api/ux/company/screens/{screen}
Owner / CFO: make a layout the company default of one screen (null = clear).
| Field | Where | Required | Notes |
|---|---|---|---|
screen | path | yes | |
layout | body (object/null) | {tiles:[{id,w,h,hidden,colour}], columns:[{id,width,hidden,pin}], collapsed:{group:bool}}; null = standard |
GET /api/ux/company/share-limits
The sharing cap in force (own mail account: the company's choice; our system address: our fixed cap, which can only be lowered).
PUT /api/ux/company/share-limits
Owner / CFO: how many people one person may mail per hour and the company per day.
| Field | Where | Required | Notes |
|---|---|---|---|
per_user_hour | body (integer/null) | recipients one person may mail per hour; empty = no limit (own mail account only) | |
per_company_day | body (integer/null) | recipients the whole company may mail per day; empty = no limit (own mail account only) |
POST /api/ux/news/seen
I have read "What's new" up to this release.
| Field | Where | Required | Notes |
|---|---|---|---|
version | body (string) | yes |
GET /api/ux/people
People of this company for the @-mention picker (never anyone outside the company; never me).
| Field | Where | Required | Notes |
|---|---|---|---|
q | query |
GET /api/ux/screens/{screen}
The layout I see on one screen: mine, else the company default, else the standard.
| Field | Where | Required | Notes |
|---|---|---|---|
screen | path | yes |
PUT /api/ux/screens/{screen}
Save MY layout of one screen (cards moved / resized / hidden / coloured, table columns, collapsed groups).
| Field | Where | Required | Notes |
|---|---|---|---|
screen | path | yes | |
layout | body (object/null) | {tiles:[{id,w,h,hidden,colour}], columns:[{id,width,hidden,pin}], collapsed:{group:bool}}; null = standard |
POST /api/ux/screens/{screen}/reset
Reset one screen of mine: back to the company default (or the standard).
| Field | Where | Required | Notes |
|---|---|---|---|
screen | path | yes |
POST /api/ux/share
Send it to @people: e-mail a link to a record or screen to people of this company whose role may see it.
| Field | Where | Required | Notes |
|---|---|---|---|
kind | body (string) | yes | |
recipients | body (array) | yes | Company people (user ids) from /api/ux/people |
ref_kind | body (string/null) | document, entry, stock_doc, import_batch, fx_revaluation, party, item, account, ... | |
ref_id | body (string/null) | ||
path | body (string/null) | For kind=screen: the screen path, e.g. | |
note | body (string) |
GET /api/ux/suggest
Suggest me: the next best actions for me on this screen, each counted from the company's real records just now.
| Field | Where | Required | Notes |
|---|---|---|---|
screen | query |
PUT /api/ux/theme
My look: light / dark, density, text and background colour (must stay readable), accent colour.
| Field | Where | Required | Notes |
|---|---|---|---|
theme | body (object/null) | {mode, density, text, background, accent}; text on background must be 4.5:1; null = standard |
GET /api/ux/workspace
My theme, my screen layouts, the company's brand colour and default layouts, and whether I may change the company's.