Directory (shared master data): Contacts, Addresses, Products
Customers & Suppliers is shared by Sales, Purchases, Collections and Compliance and sits in the Directory sidebar group, not under Sales. The contact and address endpoints carry no permission gate: every active member of the tenant may read and write them (authentication and tenant scope still apply; read-only API keys are still refused on writes).
| Method & Path | Permission | Purpose |
|---|---|---|
GET/POST contacts, PATCH contacts/{contact} | any member | Customer/supplier master |
GET contacts/{contact}/suggested-tax-rates | any member | Place-of-supply tax suggestion (Canadian provinces; empty elsewhere) |
GET/POST contacts/{contact}/addresses, PUT/DELETE .../{address} | any member | Multi-address per contact |
POST contacts/{contact}/addresses/copy-billing-to-shipping | any member | Clone default billing → shipping |
POST .../addresses/{address}/set-default-billing | /set-default-shipping | any member | Set default address |
GET/POST products, GET products/{product}, PUT products/{product} | product.view/product.manage | Catalogue |
GET products/export / POST products/import | product.export/product.import | CSV in/out (all-or-nothing import) |
POST products/{product}/activate | /deactivate | /duplicate | product.manage | Lifecycle actions |
GET/POST product-categories, PUT/DELETE .../{category} | product.view/product.manage | Hierarchical categories |
Quotations & Sales Orders
Identical route shape registered twice — quotations and sales-orders — with one difference: a sales order can only convert to an invoice (target_kind=invoice).
Method & Path ({path} = quotations | sales-orders) | Permission | Purpose | Side effects |
|---|---|---|---|
GET {path} / GET {path}/{document} | sales.view | List / detail | — |
POST {path} | sales.manage | Create draft | No GL posting for these kinds |
PUT {path}/{document} / DELETE {path}/{document} | sales.manage | Edit / delete draft | — |
GET {path}/{document}/pdf / /history | sales.view | PDF / lifecycle history | — |
POST {path}/{document}/send | /accept | /decline | /expire | sales.manage | Lifecycle status | — |
POST {path}/{document}/convert | sales.manage | Convert to sales order/invoice | Creates a new linked CommercialDocument |
Invoices
| Method & Path | Permission | Feature gate | Purpose | Side effects |
|---|---|---|---|---|
GET invoices / GET invoices/{document} | sales.view | — | List / detail | — |
POST invoices | sales.manage | — | Create draft | Optional captured_payment object (point-of-sale capture, see below) |
PUT invoices/{document} / DELETE invoices/{document} | sales.manage | — | Edit/delete draft | PUT accepts the same optional captured_payment |
GET invoices/{document}/pdf / /history / /payments | sales.view | — | PDF / history / settlement summary | — |
POST invoices/{document}/submit | /review | /approve | /reject | /reverse | sales.submit/review/approve/reject/reverse | — | Workflow transitions | approve posts to ledger (402 usage_limit_reached at the monthly transaction cap); reverse submits a reversing entry for approval |
GET/POST invoices/{document}/einvoice, POST .../einvoice/submit | sales.view/sales.manage | feature:e_invoicing | Country e-invoice (ZATCA/PEPPOL/PH EIS/JP) | External transport call (no-op NullTransport by default) |
GET/POST invoices/{document}/attachments | sales.view/sales.manage | — | Attachments | Stores file (10MB cap), audit |
GET invoices/{document}/deliveries | sales.view | — | Email delivery history | — |
POST invoices/{document}/send | sales.manage | — | Email invoice PDF | Sends email, records InvoiceDelivery |
POST invoices/{document}/resend/{delivery} | sales.manage | — | Resend using a prior delivery's recipient/cc | Sends email |
Point-of-sale capture (captured_payment)
The former one-step POST invoices/cash-sale endpoint (and the tenant opt-in allow_cash_sale_direct_post) has been removed. For a sale paid at the counter, send an optional captured_payment object on POST/PUT invoices: cash_account_id (required — a cash/bank GL account), payment_method (default cash; check_number required for check), reference, check_number, gateway_transaction_id, bank_account_id. It is validated at capture and returned on the invoice resource. Nothing posts at capture: the invoice goes through its normal review/approval; when its approval posts it, the same transaction drafts the payment with the invoice creator as preparer, allocated to the invoice, and submits it for its own review and approval. The invoice is settled when that payment posts. Each posting consumes its own unit of the monthly transaction cap.
Customer credits
| Method & Path | Permission | Purpose | Side effects |
|---|---|---|---|
GET customer-credits / GET customer-credits/{credit} | payment.view | List / detail | Each row carries pending_request (the open apply/refund sign-off, or null) |
POST customer-credits/{credit}/apply | payment.manage | Request applying the credit to a posted invoice (document_id, amount, optional reason) | 202 with an approval-request row (domain payment, action credit_apply); posts nothing yet |
POST customer-credits/{credit}/refund | payment.manage | Request a cash refund (cash_account_id, optional amount, reason) | 202 with an approval-request row (action credit_refund); posts nothing yet |
POST customer-credits/{credit}/void | payment.manage | Void an unapplied credit | — |
Apply/refund requests are decided through the shared approval-request endpoints with domain=payment: GET approval-requests?domain=payment (+ /{id}, /{id}/history) need payment.view; the maker can PATCH (edit the amount) / submit / withdraw a draft (payment.submit); POST approval-requests/{id}/review needs payment.review, /approve needs payment.approve, /reject needs payment.reject. Only one open request per credit. Maker, reviewer and approver must be three different users; approval posts the application/refund and the resulting journal entry carries the request's maker, reviewer and approver. Web: Collections → Credit Approvals (/app/customer-credits/approvals).
Credit Notes & Debit Notes
Same CRUD + workflow shape as invoices, permission sales.*, at credit-notes (kind=credit_note) and debit-notes (kind=debit_note). Approving a credit note posts the reverse of an invoice's entries (Dr revenue / Cr AR) and reduces the linked invoice's outstanding balance when one is set; a debit note posts like an invoice (Dr AR / Cr revenue + output tax) representing an EOPT upward sales adjustment. Both support the same e-invoice lifecycle as invoices.
Recurring Invoices (recurring-invoices)
Same shape as recurring journal entries — permission sales.view/sales.manage. A source_document_id must reference an approved and posted invoice (422 otherwise).