Purchasing API notes
This page is for the developer whose system posts purchase documents: which document types the module
produces, how knock-off against an order or a goods receipt looks from outside, and what to poll after
FINAL. It is the purchasing part only. There is one API for the whole platform, with no separate
Purchasing API and no separate host for it, so the path grammar, access endpoints, authentication,
paging, response envelopes and error codes are on the developer integration path.
The fast path for a purchase document your system posts:
- Read the source document’s open-queue rows; link only a line that still has open quantity (knock-off).
- Create the document by its server document type and write the document link to the source line. If you post invoices yourself, the GRN auto-convert must be off for that pair.
- Set it
FINAL, then poll its Journal, Inventory and Tax posting statuses rather than reading balances straight back.
The document types this module produces
All of them are generic documents, reachable through the generic document endpoints by their server document type:
INTERNAL_PURCHASE_REQUISITION · INTERNAL_PURCHASE_QUOTATION · INTERNAL_BLANKET_PURCHASE_ORDER ·
INTERNAL_PURCHASE_ORDER · INTERNAL_PURCHASE_GOODS_RECEIVED_NOTE · INTERNAL_PURCHASE_GRN_STOCK_IN ·
INTERNAL_PURCHASE_GOODS_ISSUED_NOTE · INTERNAL_PURCHASE_INVOICE ·
INTERNAL_PURCHASE_INVOICE_NO_STOCK_IN · INTERNAL_PURCHASE_RETURN · INTERNAL_PURCHASE_DEBIT_NOTE ·
INTERNAL_PURCHASE_CREDIT_NOTE · INTERNAL_PURCHASE_REFUND_NOTE ·
INTERNAL_PURCHASE_CONSIGNMENT_ORDER · INTERNAL_PURCHASE_CONSIGNMENT_GRN ·
INTERNAL_PURCHASE_CONSIGNMENT_GIN · INTERNAL_PURCHASE_CONSIGNMENT_RETURN ·
INTERNAL_PURCHASE_CONSIGNMENT_INVOICE
Each applet’s reference page names the four API permissions its document type needs.
Consignor Purchase Billing is not a generic document. It writes its own billing tables through
its own resource; there is no FINAL, no journal and no open queue behind it. The Supplier Delivery
Order applet writes the tenant’s ordinary INTERNAL_OUTBOUND_DELIVERY_ORDER, not a purchase type.
How knock-off looks from outside
Knock-off is two tables, not a field. When a document goes FINAL, a processor reads the company’s knock-off configuration and writes one line open-queue row per line for each enabled downstream type, carrying the open quantity. A downstream document that knocks a line off writes a document link between the two and reduces the queue row’s open quantity.
Four consequences for an integration:
- A document you create through the API is knocked off by writing the link, not by naming the source on the new document. Read the source’s open-queue rows first; a fully knocked-off line has no open quantity and must not be linked again.
- Write the link through the links endpoint, after the document exists. The open quantity of a
source line that has a queue row falls when the link arrives by
POST /core2/tnt/dm/erp/generic-doc/links/backoffice-ep, the call the GRN applet makes once a receipt is saved. Where no queue row matches, the call still succeeds and nothing falls, so read the row back. A link carried inside thebl_fi_generic_doc_linkarray of the document you create is stored, but the queue row keeps its full open quantity, so the source line still shows as open to the next person who knocks off against it. - The queue exists only where the configuration says so. A finalised order in a company with no order → GRN row has no queue rows, and nothing downstream can find it.
- Two backend converters copy a receipt into its invoice — plain GRN → Purchase Invoice, and GRN Stock In → No Stock In invoice — with the links already written. The company’s document-flow configuration decides whether they run and whether the result is DRAFT or FINAL. If you post invoices yourself, make sure the auto-convert is off for that pair, or you will get two.
Two things an integration must respect
The signums are the server’s, not yours. A document type’s quantity and amount signums are fixed in the backend, and the applet’s own copy is overwritten on every save. Sending a quantity signum of +1 on a plain GRN changes nothing; if you need the receipt to move stock you post a GRN Stock In, and you then bill with a No Stock In invoice. The receiving pair is a document-type choice, and an integration that mixes the pairs double-counts exactly as a user does.
Posting is asynchronous. Setting a purchase invoice to FINAL queues the work: one processor
writes the journal, another the stock ledger lines, others the tax, cashbook and e-Invoice queues.
An integration that finalises and immediately reads the supplier’s balance or the stock balance can
legitimately see the old figure. Poll the document’s posting statuses — Journal, Inventory, Tax —
rather than reading straight back. The _UPDATED webhook is sent when the FINAL is saved, before
those processors run, so it is not the signal that anything posted. A journal that fails (a missing
default GL code, most often) leaves the document FINAL with that status unposted; for a GRN Stock In
the stock is already in.
What the API will not do for you
There is no matching endpoint, no tolerance check and no approval gate. An invoice posted with a price different from its knocked-off order finalises. If you need a variance rule, it lives in your system before you post.