Purchase order ( purchase_order )
A purchase_order is an order issued by a merchant to a supplier. It carries amounts, line items, and progress status and serves as the anchor for supplier invoices received in return.
Role
The purchase order is the entry object for the Accounts Payable (AP) lifecycle. It formalizes the merchant's commitment to a supplier before goods or services are delivered and invoiced. Its lifecycle follows the operational journey: drafting → internal approval → sending to supplier → receipt → closure.
Received supplier invoices may be created directly from the purchase order or linked afterward. Invoice lines may reference purchase-order lines for precise matching.
The supplier is a company platform object — the same objects are used for buyers in AR flows and suppliers in AP flows.
Identifier and structure
Each purchase order has a stable identifier prefixed with po_.
{
"object": "purchase_order",
"id": "po_3c8f1a9b2d4e7f6a",
"merchant_id": "mer_1a2b3c4d5e6f7a8b",
"supplier_id": "cmp_9b2e4f1a7c3d8e5f",
"supplier_contact_id": null,
"source_reference": "erp::tenant-42::purchase_order::158",
"reference": "PO-2026-00158",
"supplier_order_reference": "CONF-SUP-8741",
"delivery_details": {
"address": {
"line1": "4 rue des Ateliers",
"city": "Lyon",
"postal_code": "69007",
"country": "FR"
}
},
"status": "sent",
"currency": "eur",
"amount_excluding_tax": 250000,
"amount_tax": 50000,
"amount_including_tax": 300000,
"metadata": {},
"approved_at": "2026-06-17T09:00:00.000Z",
"sent_at": "2026-06-17T10:30:00.000Z",
"cancelled_at": null,
"fulfilled_at": null,
"completed_at": null,
"created_at": "2026-06-17T08:45:00.000Z",
"updated_at": "2026-06-17T10:30:00.000Z"
}Fields
| Field | Type | Description |
|---|---|---|
id | string | Purchase-order identifier (prefix `po_`). |
object | string | Always "purchase_order". |
merchant_id | string | Issuing merchant. |
supplier_id | string | Recipient supplier (`cmp_…`). Required at creation. |
supplier_contact_id | string | null | Supplier contact (`ctc_…`). Optional. |
source_reference | string | null | Identity or provenance of the purchase order in your source system. |
reference | string | null | Business purchase-order number assigned by the merchant. |
supplier_order_reference | string | null | Order number or confirmation assigned by the supplier in response to the purchase order. |
delivery_details | object | null | Open shipping or destination information useful to the P2P flow. |
status | enum | Purchase-order status: `draft`, `approved`, `sent`, `cancelled`, `fulfilled`, `completed`. |
currency | string | ISO 4217 currency code in lowercase (for example `eur`). |
amount_excluding_tax | integer | Amount excluding tax in cents. |
amount_tax | integer | Tax amount in cents. |
amount_including_tax | integer | Amount including tax in cents. Constraint: excluding tax + tax = including tax. |
metadata | object | Flat map of `string | number | boolean` scalars, following the API metadata convention. |
approved_at | datetime | null | Internal approval timestamp. |
sent_at | datetime | null | Timestamp when sent to the supplier. |
cancelled_at | datetime | null | Cancellation timestamp. |
fulfilled_at | datetime | null | Timestamp of receipt of goods or services. |
completed_at | datetime | null | Accounting-closure timestamp. |
created_at | datetime | Creation date. |
updated_at | datetime | Last update date. |
Lifecycle
The purchase order follows a linear lifecycle from drafting to closure. Only status draft is editable.
Statuses
| Status | Description | Final |
|---|---|---|
draft | Draft. Editable — amounts, lines, contact. Only possible initial status. | no |
approved | Approved internally. Not editable. | no |
sent | Sent to the supplier. | no |
fulfilled | Goods or services received. | no |
completed | Closed — accounting processing complete. | yes |
cancelled | Canceled. Reachable from `draft`, `approved`, or `sent`. | yes |
Transitions
| Action | Endpoint | From | To | Timestamp populated |
|---|---|---|---|---|
| Approuver | POST /:id/approve | draft | approved | approved_at |
| Envoyer | POST /:id/send | approved | sent | sent_at |
| Receive | POST /:id/fulfill | approved, sent | fulfilled | fulfilled_at |
| Close | POST /:id/complete | fulfilled | completed | completed_at |
| Annuler | POST /:id/cancel | draft, approved, sent | cancelled | cancelled_at |
Progress timestamps are cumulative: moving directly from
approved to fulfilled also populates
sent_at. Moving from draft to
fulfilled also populates approved_at and sent_at
with the same timestamp. Likewise, complete populates
fulfilled_at if it was still null.
Lignes d'article
Line items describe the products or services ordered. They may be supplied at creation and atomically replaced during update while the purchase order is in draft). They are available through
GET /v1/purchase-orders/:id/line-items.
| Field | Type | Description |
|---|---|---|
id | string | Line identifier (prefix `li_`). |
product_name | string | Product or service name. Required. |
description | string | null | Additional description. |
product_reference | string | null | Product reference in your catalog. |
quantity | integer | Quantity (positive integer). |
unit_amount_excluding_tax | integer | Unit price excluding tax in cents. |
unit_amount_including_tax | integer | Unit price including tax in cents. |
amount_excluding_tax | integer | Line amount excluding tax (= `unit_ht` × `quantity` when absent). |
amount_tax | integer | Line tax amount. |
amount_including_tax | integer | Line amount including tax (= `unit_ttc` × `quantity` when absent). |
currency | string | Currency. Must match the purchase-order currency. |
If amount_excluding_tax or amount_including_tax is not supplied, it is calculated automatically (unit_amount × quantity).
The excluding tax + tax = including tax constraint applies to every line.
Supplier-invoice lines may reference a purchase-order line through purchase_order_line_item_id for line-by-line matching.
Supplier invoices
A purchase order may be associated with one or more supplier invoices through a many-to-many relationship. An invoice may also be linked to several purchase orders, for example partial deliveries across several POs.
Create an invoice from the purchase order
POST /v1/purchase-orders/:id/supplier-invoices creates a supplier invoice that automatically inherits the purchase-order currency and establishes the relationship between the two objects.
POST /v1/purchase-orders/po_3c8f/supplier-invoices
{
"type": "invoice",
"amount_excluding_tax": 250000,
"amount_tax": 50000,
"amount_including_tax": 300000,
"reference": "SUPPLIER-INVOICE-2026-0042",
"issue_date": "2026-06-17",
"received_at": "2026-06-18T09:00:00.000Z",
"due_date": "2026-07-17"
}The invoice is created with status = received,
settlement_status = unpaid and disputed = false. These three pieces of information evolve independently: receipt/approval, settlement, and dispute.
Link existing invoices
| Endpoint | Effet |
|---|---|
GET /v1/purchase-orders/:id/supplier-invoices | Lists linked supplier invoices. |
POST /v1/purchase-orders/:id/supplier-invoice-links | Atomically replaces the complete set of links. Send { "supplier_invoice_ids": ["si_ …"] }. |
DELETE /v1/purchase-orders/:id/supplier-invoice-links/:supplier_invoice_id | Removes one link without affecting others. |
Links can also be managed from the supplier invoice through
POST /v1/supplier-invoices/:id/purchase-order-links.
In processes
There is no dedicated node for creating or transitioning a purchase order. The object is managed through direct API calls or HTTP actions in an orchestration process.
The purchase order can be passed as typed input in a process — it can be retrieved through the generic helper fetch_purchase_order from its identifier.
In a typical AP flow, the process is triggered by a receipt event (purchase_order.fulfilled or supplier_invoice.received), then orchestrates invoice approval and supplier payment.
Events
| Event | Trigger |
|---|---|
purchase_order.created | Purchase order created. |
purchase_order.updated | Purchase order updated — amounts, lines, contact. |
purchase_order.approved | Moved to `approved`. |
purchase_order.sent | Moved to `sent`. |
purchase_order.fulfilled | Moved to `fulfilled` — receipt confirmed. |
purchase_order.completed | Moved to `completed` — accounting closure. |
purchase_order.cancelled | Moved to `cancelled`. |
Transition events include final status in their payload. The payload also contains supplier_id so processes can filter events by supplier.