Close the books in 2 days, not 2 weeks — POS, inventory and multi-branch on one ledger.Read the case study →
Developers · API v1

Your books, programmable.

The same double-entry ledger that runs your workspace — invoices, bills, payments, stock, journal entries and reports — as a REST API, signed webhooks and an MCP server for AI agents. One token. Your permissions. Never more.

Request
curl "https://app.nonari.io/api/v1/invoices?status=OVERDUE" \
  -H "Authorization: Bearer $NONARI_TOKEN"
Response · 200 · trimmed
{
  "data": [
    {
      "id": "cmf3v9x2k0001qd08a1b2c3d4",
      "number": "INV-0142",
      "status": "OVERDUE",
      "currency": "USD",
      "total": "2350",
      "amountDue": "1840",
      "dueDate": "2026-09-01T00:00:00.000Z",
      "contact": { "displayName": "Harbor Supply Co." }
    }
  ],
  "meta": { "page": 1, "perPage": 20, "total": 1, "hasMore": false }
}
262
REST endpoints across sales, purchases, banking, stock, ledger and reports.
57
signed webhook events, from invoice.created to stock_movement.deleted.
33
MCP tools for Claude and other AI agents.
600
requests a minute per token, with the budget in every response.
Quick start

From token to posted invoice in three requests.

1

Create a token

In the app, open Settings → API Access Tokens → New token. Choose Full access or Read-only, pick an expiry, and copy the token — it is shown once. Then export NONARI_TOKEN=nonari_…

Check who you are
curl https://app.nonari.io/api/v1/me \
  -H "Authorization: Bearer $NONARI_TOKEN"
2

Add a customer

Every write is validated before it touches the ledger. A bad body answers 422 with every invalid field listed in details.

POST /contacts
curl -X POST https://app.nonari.io/api/v1/contacts \
  -H "Authorization: Bearer $NONARI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "displayName": "Harbor Supply Co.", "type": "CUSTOMER", "email": "ap@harbor.example" }'
3

Invoice them — posted

"status": "SENT" posts the invoice on creation: receivable, revenue and tax, balanced, in one transaction. Leave it out to create a draft and post it later with POST /invoices/{id}/send.

POST /invoices
curl -X POST https://app.nonari.io/api/v1/invoices \
  -H "Authorization: Bearer $NONARI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "contactId": "<id from the contact you just created>",
    "issueDate": "2026-09-23T00:00:00.000Z",
    "status": "SENT",
    "lines": [
      { "description": "Consulting — September", "quantity": 10, "unitPrice": 120 }
    ]
  }'
How it behaves

The rules, stated once.

Authentication

Authorization: Bearer nonari_… on every request. A token is bound to one workspace and acts as the person who created it — the same permissions, the same branches. Revoke it and the next request fails.

Read-only tokens

A read-only token can view and export everything its creator can, and cannot create, edit, post, pay, void or delete anything. Its limits are checked on every request, against the creator’s current permissions.

Branches

In a multi-branch workspace, send X-Nonari-Branch: <branch id> (ids from GET /branches) to read and write inside one branch. Without it, reads are consolidated across the branches the token can see.

Responses and errors

Success is { "data": … }. Errors are { "error": { "code", "message" } } — 401, 403, 404, 409 for a locked period or a conflict, 422 with field-level details, 429 when rate-limited.

Pagination

Lists take ?page= and ?perPage= and answer with meta: { page, perPage, total, hasMore }. Filters are plain query parameters — every one is listed in the reference below.

Limits

600 requests a minute per token. Each response carries X-RateLimit-Remaining, X-RateLimit-Reset and an X-Request-Id to quote when you write to us.

Money and dates

Amounts come back as decimal strings — exact, never passed through floating point. Send amounts as JSON numbers and dates as ISO-8601.

Browsers

Token requests are CORS-enabled, so a browser-side integration can call the API directly. Cookies are never accepted cross-origin: a token is the only credential.

Reference

Every endpoint, with the permission it checks.

Paths are relative to https://app.nonari.io/api/v1. The same list, with request bodies, lives in the OpenAPI 3.1 description — import it into Postman or an SDK generator.

IdentityWho the token belongs to, and what it may do.3 endpoints
GET/api/v1/meWho is calling: user, workspace, token access, branch scope and effective permissions—
GET/api/v1/me/permissionsThe caller’s effective permission state (grants, denies, per-branch overrides)—
GET/api/v1/me/roleThe caller’s role in the workspace—
SalesInvoices, credit notes, quotes, sales orders and delivery notes.50 endpoints
GET/api/v1/invoicesList invoices, newest firstinvoice:view
POST/api/v1/invoicesCreate an invoice — a draft by default; "status": "SENT" posts it to the ledger. Send "replacesId" to edit an existing invoice.invoice:create
GET/api/v1/invoices/{id}Retrieve an invoice with its lines and paymentsinvoice:view
PATCH/api/v1/invoices/{id}Move an invoice to SENT or VOID, or change fields that do not touch the ledger (reference, notes, terms, footer, due date, salesperson, display options, custom fields)invoice:edit
DELETE/api/v1/invoices/{id}Delete an invoice and reverse everything it postedinvoice:delete
POST/api/v1/invoices/{id}/sendPost a draft invoice to the ledger (receivable, revenue, tax, cost of sales)invoice:create
POST/api/v1/invoices/{id}/paymentRecord a payment against an invoiceinvoice:pay
DELETE/api/v1/invoices/{id}/payment/{paymentId}Remove a payment recorded against an invoiceinvoice:pay
POST/api/v1/invoices/{id}/voidVoid an invoice, reversing its postingsinvoice:void
GET/api/v1/invoices/{id}/pdfDownload the invoice as a PDFinvoice:view
POST/api/v1/invoices/{id}/emailEmail the invoice to the customerinvoice:create
POST/api/v1/invoices/{id}/send-smsText the invoice link to the customerinvoice:create
POST/api/v1/invoices/{id}/shareCreate a public link to view and pay the invoiceinvoice:create
DELETE/api/v1/invoices/{id}/shareRevoke the invoice’s public linkinvoice:create
POST/api/v1/invoices/{id}/change-customerMove an invoice to a different customerinvoice:edit
GET/api/v1/invoices/{id}/shipmentDelivery status of an invoice’s goodsdeliveryNote:view
GET/api/v1/invoices/{id}/fbr-statusTax-authority e-invoicing status of an invoiceinvoice:view
GET/api/v1/invoices/overdueInvoices past their due dateinvoice:view
POST/api/v1/invoices/bulkOne action on many invoices: "send", "void", "mark_paid" or "delete" (each needs its own permission)—
GET/api/v1/credit-notesList credit notescreditNote:view
POST/api/v1/credit-notesCreate a credit note against a customer, optionally linked to an invoicecreditNote:create
GET/api/v1/credit-notes/{id}Retrieve a credit notecreditNote:view
PATCH/api/v1/credit-notes/{id}Update a credit notecreditNote:edit
DELETE/api/v1/credit-notes/{id}Delete a credit note and reverse its postingscreditNote:delete
GET/api/v1/credit-notes/{id}/pdfDownload the credit note as a PDFcreditNote:view
POST/api/v1/credit-notes/{id}/refundRefund a credit note to the customer from a bank or cash accountcreditNote:create
GET/api/v1/sales-quotesList sales quotessalesQuote:view
POST/api/v1/sales-quotesCreate a sales quotesalesQuote:create
GET/api/v1/sales-quotes/{id}Retrieve a sales quotesalesQuote:view
PATCH/api/v1/sales-quotes/{id}Update a sales quote or change its statussalesQuote:edit
DELETE/api/v1/sales-quotes/{id}Delete a sales quotesalesQuote:delete
POST/api/v1/sales-quotes/{id}/acceptAccept a quote: creates and posts the invoice and marks the quote convertedinvoice:create
POST/api/v1/sales-quotes/{id}/convert-to-orderConvert a quote into a sales ordersalesOrder:create
GET/api/v1/sales-quotes/{id}/pdfDownload the sales quote as a PDFsalesQuote:view
GET/api/v1/sales-ordersList sales orderssalesOrder:view
POST/api/v1/sales-ordersCreate a sales ordersalesOrder:create
GET/api/v1/sales-orders/{id}Retrieve a sales ordersalesOrder:view
PATCH/api/v1/sales-orders/{id}Update a sales order or change its statussalesOrder:edit
DELETE/api/v1/sales-orders/{id}Delete a sales ordersalesOrder:delete
POST/api/v1/sales-orders/{id}/convert-to-invoiceInvoice a sales orderinvoice:create
POST/api/v1/sales-orders/{id}/convert-to-delivery-noteCreate a delivery note from a sales orderdeliveryNote:create
GET/api/v1/sales-orders/{id}/pdfDownload the sales order as a PDFsalesOrder:view
GET/api/v1/delivery-notesList delivery notesdeliveryNote:view
POST/api/v1/delivery-notesCreate a delivery notedeliveryNote:create
GET/api/v1/delivery-notes/{id}Retrieve a delivery notedeliveryNote:view
PATCH/api/v1/delivery-notes/{id}Update a delivery notedeliveryNote:edit
DELETE/api/v1/delivery-notes/{id}Delete a delivery notedeliveryNote:delete
GET/api/v1/delivery-notes/{id}/pdfDownload the delivery note as a PDFdeliveryNote:view
GET/api/v1/delivery-notes/invoice-searchFind invoices to deliver againstdeliveryNote:view
GET/api/v1/delivery-notes/transfer-searchFind inventory transfers to shipdeliveryNote:view
PurchasesBills, debit notes, purchase orders and quotes, goods receipts and expenses.48 endpoints
GET/api/v1/billsList supplier bills, newest firstbill:view
POST/api/v1/billsCreate a supplier bill. Send "replacesId" to edit an existing bill.bill:create
GET/api/v1/bills/{id}Retrieve a bill with its lines and paymentsbill:view
PATCH/api/v1/bills/{id}Approve or void a bill, or change fields that do not touch the ledgerbill:edit
DELETE/api/v1/bills/{id}Delete a bill and reverse everything it postedbill:delete
POST/api/v1/bills/{id}/paymentRecord a payment against a billbill:pay
DELETE/api/v1/bills/{id}/payment/{paymentId}Remove a payment recorded against a billbill:pay
POST/api/v1/bills/{id}/voidVoid a bill, reversing its postingsbill:void
GET/api/v1/bills/{id}/pdfDownload the bill as a PDFbill:view
POST/api/v1/bills/{id}/emailEmail the billbill:create
POST/api/v1/bills/bulkOne action on many bills: "void", "mark_paid" or "delete" (each needs its own permission)—
GET/api/v1/debit-notesList debit notesdebitNote:view
POST/api/v1/debit-notesCreate a debit note against a supplierdebitNote:create
GET/api/v1/debit-notes/{id}Retrieve a debit notedebitNote:view
PATCH/api/v1/debit-notes/{id}Update a debit notedebitNote:edit
DELETE/api/v1/debit-notes/{id}Delete a debit note and reverse its postingsdebitNote:delete
GET/api/v1/debit-notes/{id}/pdfDownload the debit note as a PDFdebitNote:view
POST/api/v1/debit-notes/{id}/refundRecord the supplier’s refund of a debit note into a bank or cash accountdebitNote:create
GET/api/v1/purchase-ordersList purchase orderspurchaseOrder:view
POST/api/v1/purchase-ordersCreate a purchase orderpurchaseOrder:create
GET/api/v1/purchase-orders/{id}Retrieve a purchase orderpurchaseOrder:view
PATCH/api/v1/purchase-orders/{id}Update a purchase order or change its statuspurchaseOrder:edit
DELETE/api/v1/purchase-orders/{id}Delete a purchase orderpurchaseOrder:delete
POST/api/v1/purchase-orders/{id}/convert-to-billBill a purchase orderbill:create
POST/api/v1/purchase-orders/{id}/convert-to-goods-receiptReceive a purchase order’s goodsgoodsReceipt:create
GET/api/v1/purchase-orders/{id}/pdfDownload the purchase order as a PDFpurchaseOrder:view
GET/api/v1/purchase-orders/{id}/receipt-statusHow much of each purchase-order line has been receivedgoodsReceipt:view
GET/api/v1/purchase-quotesList purchase quotespurchaseQuote:view
POST/api/v1/purchase-quotesCreate a purchase quotepurchaseQuote:create
GET/api/v1/purchase-quotes/{id}Retrieve a purchase quotepurchaseQuote:view
PATCH/api/v1/purchase-quotes/{id}Update a purchase quotepurchaseQuote:edit
DELETE/api/v1/purchase-quotes/{id}Delete a purchase quotepurchaseQuote:delete
POST/api/v1/purchase-quotes/{id}/convertConvert a purchase quote into a purchase orderpurchaseOrder:create
POST/api/v1/purchase-quotes/{id}/convert-to-billConvert a purchase quote straight into a billbill:create
GET/api/v1/purchase-quotes/{id}/pdfDownload the purchase quote as a PDFpurchaseQuote:view
GET/api/v1/goods-receiptsList goods receiptsgoodsReceipt:view
POST/api/v1/goods-receiptsRecord goods received into stockgoodsReceipt:create
GET/api/v1/goods-receipts/{id}Retrieve a goods receiptgoodsReceipt:view
PATCH/api/v1/goods-receipts/{id}Update a goods receiptgoodsReceipt:edit
DELETE/api/v1/goods-receipts/{id}Delete a goods receipt and reverse its stockgoodsReceipt:delete
GET/api/v1/goods-receipts/{id}/pdfDownload the goods receipt as a PDFgoodsReceipt:view
GET/api/v1/expensesList expensesexpense:view
POST/api/v1/expensesRecord an expenseexpense:create
GET/api/v1/expenses/{id}Retrieve an expenseexpense:view
PATCH/api/v1/expenses/{id}Update an expenseexpense:edit
DELETE/api/v1/expenses/{id}Delete an expense and reverse its postingsexpense:delete
GET/api/v1/expenses/{id}/pdfDownload the expense as a PDFexpense:view
POST/api/v1/expenses/bulkDelete many expenses at onceexpense:delete
BankingBank and cash accounts, their transactions, receipts, payments and transfers.25 endpoints
GET/api/v1/bank-accountsList bank and cash accounts with balancesbank:view
POST/api/v1/bank-accountsCreate a bank or cash accountbank:create
GET/api/v1/bank-accounts/{id}Retrieve a bank or cash accountbank:view
PATCH/api/v1/bank-accounts/{id}Update a bank or cash accountbank:edit
DELETE/api/v1/bank-accounts/{id}Delete a bank or cash accountbank:delete
GET/api/v1/bank-accounts/{id}/balanceCurrent balance of a bank or cash accountbank:view
POST/api/v1/bank-accounts/{id}/revalueRevalue a foreign-currency account at a new rate, posting the exchange gain or lossbank:edit
GET/api/v1/bank-transactionsList bank transactionsbankTransaction:view
POST/api/v1/bank-transactionsRecord a bank transactionbankTransaction:create
GET/api/v1/bank-transactions/{id}Retrieve a bank transactionbankTransaction:view
PATCH/api/v1/bank-transactions/{id}Update a bank transactionbankTransaction:edit
DELETE/api/v1/bank-transactions/{id}Delete a bank transactionbankTransaction:delete
POST/api/v1/banking/receiptsRecord money received into a bank or cash account (one or many lines)receipt:create
GET/api/v1/banking/receipts/{id}Retrieve a receiptreceipt:view
PATCH/api/v1/banking/receipts/{id}Update a receiptreceipt:edit
DELETE/api/v1/banking/receipts/{id}Delete a receipt and reverse its postingsreceipt:delete
GET/api/v1/banking/receipts/{id}/pdfDownload the receipt as a PDFreceipt:view
POST/api/v1/banking/paymentsRecord money paid out of a bank or cash account (one or many lines)payment:create
GET/api/v1/banking/payments/{id}Retrieve a paymentpayment:view
PATCH/api/v1/banking/payments/{id}Update a paymentpayment:edit
DELETE/api/v1/banking/payments/{id}Delete a payment and reverse its postingspayment:delete
GET/api/v1/banking/payments/{id}/pdfDownload the payment voucher as a PDFpayment:view
GET/api/v1/banking/transfers/{id}Retrieve a transfer between two bank or cash accountsbankTransaction:view
PATCH/api/v1/banking/transfers/{id}Update a transferbankTransaction:edit
DELETE/api/v1/banking/transfers/{id}Delete a transfer and reverse both legsbankTransaction:delete
ContactsCustomers and suppliers.9 endpoints
GET/api/v1/contactsList customers and supplierscontact:view
POST/api/v1/contactsCreate a customer or suppliercontact:create
GET/api/v1/contacts/{id}Retrieve a contactcontact:view
PATCH/api/v1/contacts/{id}Update a contactcontact:edit
DELETE/api/v1/contacts/{id}Delete a contact that nothing references (409 lists what still does)contact:delete
POST/api/v1/contacts/{id}/shareCreate a public statement link for the contactcontact:create
DELETE/api/v1/contacts/{id}/shareRevoke the contact’s public statement linkcontact:create
POST/api/v1/contacts/bulkImport, archive, restore or delete many contacts at once (each action needs its own permission)—
GET/api/v1/contacts/opening-balancesOpening receivable and payable balances by contactcontact:view
ItemsProducts, services, non-inventory items and their categories.26 endpoints
GET/api/v1/productsList products and servicesproduct:view
POST/api/v1/productsCreate a product or service, optionally with opening stockproduct:create
GET/api/v1/products/{id}Retrieve a productproduct:view
PATCH/api/v1/products/{id}Update a productproduct:edit
DELETE/api/v1/products/{id}Delete a product that nothing referencesproduct:delete
POST/api/v1/products/{id}/openingSet a product’s opening stock and its costproduct:edit
DELETE/api/v1/products/{id}/openingClear a product’s opening stockproduct:edit
POST/api/v1/products/archiveArchive or restore many products at onceproduct:edit
POST/api/v1/products/bulkCreate or update many products at once (needs product:create and/or product:edit)—
POST/api/v1/products/bulk/deleteDelete many products at onceproduct:delete
POST/api/v1/products/bulk/delete/previewPreview which products a bulk delete would remove, and why any are blockedproduct:delete
POST/api/v1/products/bulk/recodeChange the codes of many products at onceproduct:edit
GET/api/v1/products/check-codeCheck whether a product code is free—
GET/api/v1/products/exportExport the product listproduct:view
POST/api/v1/products/resolveMatch pasted names or codes to existing productsproduct:view
GET/api/v1/products/sale-ratesPer-customer and per-branch sale ratesproductSalePrice:view
PATCH/api/v1/products/sale-ratesSet sale ratesproductSalePrice:edit
GET/api/v1/non-inventory-itemsList non-inventory itemsnonInventoryItem:view
POST/api/v1/non-inventory-itemsCreate a non-inventory itemnonInventoryItem:create
PATCH/api/v1/non-inventory-items/{id}Update a non-inventory itemnonInventoryItem:edit
DELETE/api/v1/non-inventory-items/{id}Archive a non-inventory item, or delete it permanentlynonInventoryItem:delete
POST/api/v1/non-inventory-items/bulkCreate or update many non-inventory items at once—
GET/api/v1/categoriesList product categoriesproductCategory:view
POST/api/v1/categoriesCreate a product categoryproductCategory:create
PATCH/api/v1/categories/{id}Update a product categoryproductCategory:edit
DELETE/api/v1/categories/{id}Delete a product categoryproductCategory:delete
InventoryStock movements, adjustments, transfers, locations and per-branch stock.32 endpoints
GET/api/v1/stock-movementsList stock movementsstockMovement:view
POST/api/v1/stock-movementsRecord a stock movementstockMovement:create
GET/api/v1/stock-movements/{id}Retrieve a stock movementstockMovement:view
DELETE/api/v1/stock-movements/{id}Delete a stock movementstockMovement:delete
GET/api/v1/stock-movements/{id}/pdfDownload the stock movement as a PDFstockMovement:view
GET/api/v1/inventory-adjustmentsList inventory adjustmentsinventoryAdjustment:view
POST/api/v1/inventory-adjustmentsAdjust stock quantities or value (posts the gain or loss)inventoryAdjustment:create
GET/api/v1/inventory-adjustments/{id}Retrieve an inventory adjustmentinventoryAdjustment:view
PATCH/api/v1/inventory-adjustments/{id}Update an inventory adjustmentinventoryAdjustment:edit
DELETE/api/v1/inventory-adjustments/{id}Delete an inventory adjustment and reverse itinventoryAdjustment:delete
GET/api/v1/inventory-transfersList stock transfers between branches or locationsinventoryTransfer:view
POST/api/v1/inventory-transfersSend stock to another branch or locationinventoryTransfer:create
GET/api/v1/inventory-transfers/{id}Retrieve a stock transferinventoryTransfer:view
PATCH/api/v1/inventory-transfers/{id}Update a stock transferinventoryTransfer:edit
DELETE/api/v1/inventory-transfers/{id}Delete a stock transfer and reverse itinventoryTransfer:delete
POST/api/v1/inventory-transfers/{id}/receiveReceive a transfer at its destinationinventoryTransfer:create
POST/api/v1/inventory-transfers/{id}/receive-backReceive returned stock back at the senderinventoryTransfer:create
POST/api/v1/inventory-transfers/{id}/reopenReopen a received transfer for correctioninventoryTransfer:edit
POST/api/v1/inventory-transfers/{id}/conflictReport a quantity dispute on a received transferinventoryTransfer:create
POST/api/v1/inventory-transfers/{id}/excess-resolveResolve stock received beyond what was sentinventoryTransfer:create
GET/api/v1/inventory-transfers/{id}/returnReturnable quantities on a transferinventoryTransfer:view
POST/api/v1/inventory-transfers/{id}/returnReturn stock from a received transferinventoryTransfer:create
GET/api/v1/inventory-transfers/{id}/pdfDownload the stock transfer as a PDFinventoryTransfer:view
GET/api/v1/inventory-transfers/{id}/shipmentDelivery status of a transferdeliveryNote:view
POST/api/v1/inventory-transfers/bulkCreate many stock transfers at onceinventoryTransfer:create
POST/api/v1/inventory-transfers/bulk-receiveReceive many stock transfers at onceinventoryTransfer:create
GET/api/v1/inventory-locationsList warehouses and stock locationsinventoryLocation:view
POST/api/v1/inventory-locationsCreate a stock locationinventoryLocation:create
PATCH/api/v1/inventory-locations/{id}Update a stock locationinventoryLocation:edit
DELETE/api/v1/inventory-locations/{id}Archive a stock location, or delete it permanentlyinventoryLocation:delete
POST/api/v1/inventory-locations/bulkCreate or update many stock locations at once—
GET/api/v1/branches/{id}/inventoryStock on hand, by product, in one branchproduct:view
LedgerJournal entries, the chart of accounts, tax rates, currencies, projects, divisions, fixed assets and branches.47 endpoints
GET/api/v1/journal-entriesList journal entriesjournal:view
POST/api/v1/journal-entriesPost a balanced journal entry (debits must equal credits)journal:create
GET/api/v1/journal-entries/{id}Retrieve a journal entry with its linesjournal:view
PATCH/api/v1/journal-entries/{id}Update a manual journal entryjournal:edit
DELETE/api/v1/journal-entries/{id}Delete a manual journal entryjournal:delete
POST/api/v1/journal-entries/{id}/reversePost the reversing entry of a journal entryjournal:create
POST/api/v1/journal-entries/{id}/voidVoid a journal entryjournal:delete
GET/api/v1/accountsThe chart of accountsaccount:view
POST/api/v1/accountsCreate an accountaccount:create
PATCH/api/v1/accounts/{id}Update an accountaccount:edit
DELETE/api/v1/accounts/{id}Delete an account with no postingsaccount:delete
POST/api/v1/accounts/bulkCreate, update or delete many accounts at once—
GET/api/v1/tax-ratesList tax ratestax:view
POST/api/v1/tax-ratesCreate a tax ratetax:create
PATCH/api/v1/tax-rates/{id}Update a tax ratetax:edit
DELETE/api/v1/tax-rates/{id}Delete a tax ratetax:delete
POST/api/v1/tax-rates/bulkCreate or update many tax rates at once—
GET/api/v1/currenciesList the workspace’s currencies and ratescurrency:view
POST/api/v1/currenciesAdd a currencycurrency:create
PATCH/api/v1/currencies/{id}Update a currency or its ratecurrency:edit
DELETE/api/v1/currencies/{id}Remove a currencycurrency:delete
POST/api/v1/currencies/bulkAdd or update many currencies at once—
GET/api/v1/projectsList projectsproject:view
POST/api/v1/projectsCreate a projectproject:create
GET/api/v1/projects/{id}Retrieve a projectproject:view
PATCH/api/v1/projects/{id}Update a projectproject:edit
DELETE/api/v1/projects/{id}Delete a projectproject:delete
POST/api/v1/projects/bulkCreate or update many projects at once—
GET/api/v1/divisionsList divisions (profit and cost centres)division:view
POST/api/v1/divisionsCreate a divisiondivision:create
PATCH/api/v1/divisions/{id}Update a divisiondivision:edit
DELETE/api/v1/divisions/{id}Delete a divisiondivision:delete
POST/api/v1/divisions/bulkCreate or update many divisions at once—
GET/api/v1/fixed-assetsList fixed assetsfixedAsset:view
POST/api/v1/fixed-assetsRegister a fixed assetfixedAsset:create
GET/api/v1/fixed-assets/{id}Retrieve a fixed asset with its depreciationfixedAsset:view
PATCH/api/v1/fixed-assets/{id}Update a fixed assetfixedAsset:edit
DELETE/api/v1/fixed-assets/{id}Delete a fixed assetfixedAsset:delete
POST/api/v1/fixed-assets/{id}/depreciatePost depreciation for a fixed assetfixedAsset:edit
GET/api/v1/fixed-assets/{id}/depreciate/{jeId}Retrieve one depreciation postingfixedAsset:view
PATCH/api/v1/fixed-assets/{id}/depreciate/{jeId}Update one depreciation postingfixedAsset:edit
DELETE/api/v1/fixed-assets/{id}/depreciate/{jeId}Delete one depreciation postingfixedAsset:delete
POST/api/v1/fixed-assets/{id}/disposeDispose of a fixed asset, posting the gain or lossfixedAsset:edit
DELETE/api/v1/fixed-assets/{id}/disposeUndo a fixed asset’s disposalfixedAsset:edit
POST/api/v1/fixed-assets/bulkRegister or update many fixed assets at once—
GET/api/v1/branchesList branches — the ids to send as X-Nonari-Branchbranch:view
POST/api/v1/branchesCreate a branchbranch:create
ReportsFinancial statements and operational reports, as JSON or CSV.18 endpoints
GET/api/v1/reports/profit-lossProfit and loss for a periodreport.profitLoss:view
GET/api/v1/reports/balance-sheetBalance sheet at a datereport.balanceSheet:view
GET/api/v1/reports/trial-balanceTrial balance at a datereport.trialBalance:view
GET/api/v1/reports/general-ledgerGeneral ledger for an account, with running balancereport:view
GET/api/v1/reports/ar-agingReceivables aging by customerreport.arAging:view
GET/api/v1/reports/ap-agingPayables aging by supplierreport.apAging:view
GET/api/v1/reports/cash-flowCash flow statement for a periodreport.cashFlow:view
GET/api/v1/reports/cash-bookCash book for a bank or cash accountreport.cashBook:view
GET/api/v1/reports/tax-summaryTax collected and paid, by ratereport.taxSummary:view
GET/api/v1/reports/budget-vs-actualA budget against the actual ledgerreport.budgetVsActual:view
GET/api/v1/reports/low-stockProducts at or below their reorder pointreport.inventoryReorder:view
GET/api/v1/reports/partners-capitalPartners’ capital accounts for a periodreport.partnersCapital:view
GET/api/v1/reports/po-bill-matchPurchase orders matched against their billsreport.poBillMatch:view
GET/api/v1/reports/consolidated-inventory.csvStock across every branch, as CSVreport.consolidatedInventory:view
GET/api/v1/reports/consolidated-inventory.pdfStock across every branch, as PDFreport.consolidatedInventory:view
GET/api/v1/reports/inventory-aging.csvStock aging by product, as CSVreport.inventoryAging:view
GET/api/v1/reports/inventory/location-reconcileCompare each location’s stock with the branch totalinventoryLocation:view
POST/api/v1/reports/inventory/location-reconcileRe-align location stock with the branch totalinventoryLocation:manage
WebhooksSubscribe a URL to signed, real-time events.4 endpoints
GET/api/v1/webhooksList webhook subscriptions and the events they can subscribe towebhook:view
POST/api/v1/webhooksSubscribe a URL to events. The signing secret is returned once.webhook:create
PATCH/api/v1/webhooks/{id}Change a subscription’s URL, events or status, or rotate its secretwebhook:edit
DELETE/api/v1/webhooks/{id}Pause a subscription, or delete it permanentlywebhook:delete
Webhooks

Hear about every change, the moment it lands.

Subscribe a URL through the API or Settings → Webhooks. Events are fired from the audit trail, so a change made anywhere — the app, the API, the AI connector, a Shopify order — is announced the same way.

Reference ids only. The payload names the record; fetch it through the API with your own token. A leaked webhook body gives nothing away.

Signed. X-Nonari-Signature is sha256= plus the HMAC-SHA256 of the raw body, keyed with the subscription’s secret. Reject anything that does not match.

Delivered after commit. An event for a change posted inside a database transaction waits until that transaction has committed; if it rolls back, nothing is sent.

Retried. Answer any 2xx within 4 seconds. Anything else is retried twice, after about 30 seconds and about 5 minutes. X-Nonari-Delivery stays the same across retries, so you can de-duplicate on it.

Subscribe
curl -X POST https://app.nonari.io/api/v1/webhooks \
  -H "Authorization: Bearer $NONARI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "ERP sync",
    "url": "https://erp.example.com/hooks/nonari",
    "events": ["invoice.created", "invoice.payment_received", "bill.created"]
  }'
# → the response carries "secret" — shown once. Store it.
What arrives
POST /hooks/nonari
X-Nonari-Event: invoice.payment_received
X-Nonari-Delivery: 7c1d2a54-3b0e-4f5e-9a51-2f8f0f6f8a11
X-Nonari-Signature: sha256=5d41402abc4b2a76b9719d911017c592…

{
  "id": "7c1d2a54-3b0e-4f5e-9a51-2f8f0f6f8a11",
  "type": "invoice.payment_received",
  "category": "invoice",
  "createdAt": "2026-09-23T10:42:07.114Z",
  "organizationId": "cm8qz0y3d0000lk08wks12345",
  "data": { "object": "invoice_payment", "id": "cmf3wb1c40007qd08z9y8x7w6", "invoiceId": "cmf3v9x2k0001qd08a1b2c3d4" }
}
Verify it (Node.js)
import { createHmac, timingSafeEqual } from 'node:crypto'

// rawBody: the request body exactly as received, before JSON.parse
export function isFromNonari(rawBody, signatureHeader, secret) {
  const expected = 'sha256=' + createHmac('sha256', secret).update(rawBody).digest('hex')
  const a = Buffer.from(expected)
  const b = Buffer.from(signatureHeader ?? '')
  return a.length === b.length && timingSafeEqual(a, b)
}

The 57 events

invoice

invoice.createdA sales invoice was created, as a draft or posted.
invoice.updatedA sales invoice was edited.
invoice.deletedA sales invoice was deleted.
invoice.sentAn invoice was sent — posted to the ledger, or emailed or texted to the customer.
invoice.voidedAn invoice was voided and its postings reversed.
invoice.payment_receivedA payment was recorded against an invoice.
invoice.payment_deletedA payment recorded against an invoice was removed.

credit note

credit_note.createdA credit note was created.
credit_note.updatedA credit note was edited.
credit_note.deletedA credit note was deleted.

sales quote

sales_quote.createdA sales quote was created.
sales_quote.updatedA sales quote was edited.
sales_quote.deletedA sales quote was deleted.

sales order

sales_order.createdA sales order was created.
sales_order.updatedA sales order was edited.
sales_order.deletedA sales order was deleted.

delivery note

delivery_note.createdA delivery note was created.
delivery_note.updatedA delivery note was edited.
delivery_note.deletedA delivery note was deleted.

bill

bill.createdA supplier bill was created.
bill.updatedA supplier bill was edited.
bill.deletedA supplier bill was deleted.
bill.voidedA bill was voided and its postings reversed.
bill.payment_madeA payment was recorded against a bill.
bill.payment_deletedA payment recorded against a bill was removed.

debit note

debit_note.createdA debit note was created.
debit_note.updatedA debit note was edited.
debit_note.deletedA debit note was deleted.

purchase order

purchase_order.createdA purchase order was created.
purchase_order.updatedA purchase order was edited.
purchase_order.deletedA purchase order was deleted.

purchase quote

purchase_quote.createdA purchase quote was created.
purchase_quote.updatedA purchase quote was edited.
purchase_quote.deletedA purchase quote was deleted.

goods receipt

goods_receipt.createdA goods receipt was created.
goods_receipt.updatedA goods receipt was edited.
goods_receipt.deletedA goods receipt was deleted.

expense

expense.createdA expense was created.
expense.updatedA expense was edited.
expense.deletedA expense was deleted.

contact

contact.createdA customer or supplier was created.
contact.updatedA customer or supplier was edited.
contact.deletedA customer or supplier was deleted.

product

product.createdA product or service item was created.
product.updatedA product or service item was edited.
product.deletedA product or service item was deleted.

journal entry

journal_entry.createdA journal entry was created.
journal_entry.updatedA journal entry was edited or voided.
journal_entry.deletedA journal entry was deleted.

account

account.createdA chart-of-accounts account was created.
account.updatedA chart-of-accounts account was edited.
account.deletedA chart-of-accounts account was deleted.

bank transaction

bank_transaction.createdA bank transaction, receipt or payment was created.
bank_transaction.updatedA bank transaction, receipt or payment was edited.
bank_transaction.deletedA bank transaction, receipt or payment was deleted.

stock movement

stock_movement.createdA stock movement was recorded.
stock_movement.deletedA stock movement was deleted.
AI agents · Model Context Protocol

Let Claude keep the books — inside your rules.

Nonari is an MCP server. Connect Claude, or any MCP client, and it can run your reports, post entries and chase what is overdue — with exactly the permissions of the person who connected it.

Connect with OAuth. In Claude, open Settings → Connectors → Add custom connector and paste https://app.nonari.io/api/mcp. Click Connect, sign in, pick the workspace and approve. OAuth 2.1 with PKCE and dynamic client registration — no secret to handle.

Or use a token. Any client that can send a header can use the same personal access token as the REST API, including a read-only one.

Reports on request: profit & loss, balance sheet, trial balance, receivables aging, payables aging, inventory valuation, general ledger.

Read the books

whoamirun_reportlist_brancheslist_accountslist_contactslist_productslist_invoiceslist_bills

Sales and purchases

create_invoicebulk_create_invoicescreate_credit_notedelete_invoicecreate_billbulk_create_billscreate_payment

Cash and bank

create_cash_receiptcreate_expense_paymentcreate_bank_transferregister_banking_account

Ledger

bulk_create_journal_entriesdelete_journal_entriescreate_accountupdate_accountcreate_opening_balance

Contacts, items and stock

create_contactupdate_contactbulk_create_contactsarchive_contactdelete_contactcreate_productbulk_create_productscreate_inventory_adjustment

Workspace

create_branch
The same tools, over plain HTTP
curl -X POST https://app.nonari.io/api/mcp \
  -H "Authorization: Bearer $NONARI_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/call",
        "params": { "name": "run_report", "arguments": { "type": "trial_balance" } } }'
Then just ask
# “What did we make last quarter, and who still owes us?”
# “Post this month's rent: 2,400 from the operating account.”
# “Add Harbor Supply as a customer and invoice them 10 hours at 120.”

Build on books that balance.

Every plan includes the API, webhooks and the AI connector. Create a workspace, mint a token and make your first request in minutes.