Purchase execution
Review current open purchase lines, understand receiving progress, inspect the events behind each quantity, and keep supplier documents with the purchase order.
Endpoints
| Endpoint | Scope | Use it for |
|---|---|---|
GET /purchase-order-execution | purchase-order-execution:read | Review current open purchase lines with receipt state, comparable quantities, and evidence quality. |
GET /purchase-order-lines/{id}/receipt-events | purchase-order-execution:read | Read every returned receipt event for one visible purchase-order line. |
GET /purchase-orders/{id}/documents | purchase-order-execution:read | Read documents attached to one visible purchase order. |
POST /purchase-orders/{id}/documents | purchase-order-documents:write | Preview or attach one uploaded file or HTTPS document link. |
These scopes work with the acting user's current purchase-order permissions. GET /me reports effectiveCapabilities.purchaseOrders.execution, purchase-order document access, and document write readiness.
Review current purchase lines
The default view returns lines from confirmed purchase orders. Add includeDraft=true when your workflow also needs draft purchasing work.
curl "$SHELFCYCLE_API_BASE_URL/purchase-order-execution?supplierId=supplier-id&dueFrom=2026-08-01&dueTo=2026-08-31&limit=25" \
-H "Authorization: Bearer $SHELFCYCLE_API_KEY" \
-H "X-ShelfCycle-Client: Purchase follow-up"
Optional first-page filters include an exact supplierId, productId, or productFamilyId; paired dueFrom and dueTo business dates; includeDraft; and limit from 1 to 100.
Each row keeps the purchase order, supplier, product, packaging, receipt progress, operational change time, and direct receipt and document links together:
{
"data": [
{
"type": "purchase_order_execution_line",
"id": "purchase-order-line-id",
"purchaseOrder": {
"id": "purchase-order-id",
"orderNo": "PO-4812",
"externalId": "supplier-po-9021",
"status": "CONFIRMED",
"type": "STOCK_ORDER",
"dueAt": "2026-08-18T16:00:00.000Z",
"url": "https://app.shelfcycle.com/org-northstar/purchase-orders/purchase-order-id"
},
"supplier": {
"id": "supplier-id",
"displayName": "Northstar Materials",
"externalId": "SUP-104",
"url": "https://app.shelfcycle.com/org-northstar/suppliers/supplier-id"
},
"product": {
"id": "product-id",
"code": "ACETONE-PAIL",
"productFamily": { "id": "family-id", "name": "Acetone" },
"url": "https://app.shelfcycle.com/org-northstar/products/product-id"
},
"packaging": {
"id": "packaging-id",
"name": "55 gallon drum",
"type": "FIXED",
"uom": "DRUM",
"capacityUOM": "55"
},
"receiptState": "partially_received",
"evidenceQuality": "authoritative",
"expectedQuantity": {
"value": "10",
"basis": "packages",
"uom": "DRUM",
"productPackagingId": "packaging-id",
"capacityUOM": null
},
"receivedQuantity": {
"value": "6",
"basis": "packages",
"uom": "DRUM",
"productPackagingId": "packaging-id",
"capacityUOM": null
},
"remainingQuantity": {
"value": "4",
"basis": "packages",
"uom": "DRUM",
"productPackagingId": "packaging-id",
"capacityUOM": null
},
"overReceivedQuantity": {
"value": "0",
"basis": "packages",
"uom": "DRUM",
"productPackagingId": "packaging-id",
"capacityUOM": null
},
"receiptEventCount": 2,
"firstReceivedAt": "2026-08-12T14:00:00.000Z",
"lastReceivedAt": "2026-08-14T15:30:00.000Z",
"updatedAt": "2026-08-14T15:30:00.000Z",
"executionChangedAt": "2026-08-14T15:30:00.000Z",
"receiptEventsUrl": "/api/v1/purchase-order-lines/purchase-order-line-id/receipt-events",
"documentsUrl": "/api/v1/purchase-orders/purchase-order-id/documents"
}
],
"meta": {
"returnedRows": 1,
"hasMore": false,
"nextCursor": null,
"ordering": "due_at_asc_purchase_order_id_asc_line_id_asc",
"observedAt": "2026-08-14T16:00:00.000Z",
"currentState": true,
"snapshotIsolatedAcrossRequests": false,
"requestId": "request-id"
}
}
Quantities are decimal strings. Read value, basis, uom, productPackagingId, and capacityUOM together so packages and base units stay distinct.
Understand receipt state
| State | Meaning |
|---|---|
no_receipt_evidence | No receipt rows are present, so the response does not turn absence into a received quantity. |
planned_not_received | Receipt rows are planned and none has been marked received. |
quantity_basis_unknown | Receipt activity exists, but the expected and received quantities do not have enough compatible evidence for a reliable comparison. |
partially_received | The comparable received quantity is below the expected quantity. |
received_to_expected | The comparable received quantity matches the expected quantity. |
over_received | The comparable received quantity is above the expected quantity. |
When the quantity basis is unknown, the comparable aggregate fields are null. Use the receipt-event collection for the recorded activity and keep its evidence labels with each value.
Continue and refresh
When meta.hasMore is true, continue with meta.nextCursor by itself:
curl "$SHELFCYCLE_API_BASE_URL/purchase-order-execution?cursor=$NEXT_CURSOR" \
-H "Authorization: Bearer $SHELFCYCLE_API_KEY"
The list is a current view of purchase execution. executionChangedAt reports the newest recorded update across the purchase order, line, and included receipt activity. Use line id plus executionChangedAt to identify rows that deserve a fresh comparison, and periodically restart the original filtered request to reconcile the complete current view.
Inspect receipt events
Use the row's receiptEventsUrl when you need the individual activity behind its receipt state or quantity.
curl "$SHELFCYCLE_API_BASE_URL/purchase-order-lines/purchase-order-line-id/receipt-events?limit=100" \
-H "Authorization: Bearer $SHELFCYCLE_API_KEY"
Each event includes its recorded quantity, received date, lot assignment, packaging references, basis evidence, and evidence quality. Planned events remain visible with receivedAt: null. When more events are available, continue with the returned cursor alone.
Keep documents with the purchase order
Follow the row's documentsUrl, or read the documents already attached to a selected purchase order directly:
curl "$SHELFCYCLE_API_BASE_URL/purchase-orders/purchase-order-id/documents" \
-H "Authorization: Bearer $SHELFCYCLE_API_KEY"
To add a supplier confirmation, bill of lading, or other source document, prepare the private upload through POST /document-uploads, send the returned bytes, and preview the association:
curl "$SHELFCYCLE_API_BASE_URL/purchase-orders/purchase-order-id/documents?dryRun=true" \
-X POST \
-H "Authorization: Bearer $SHELFCYCLE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: purchase-order-id:document-source-id" \
-d "$(jq -n --arg fileName "$DOCUMENT_FILE_NAME" --arg url "$DOCUMENT_URL" '{fileName:$fileName,url:$url}')"
Execute the same request without dryRun=true after the readiness response matches your policy, then verify it through the purchase order's document list. The same route also accepts an existing HTTPS document link. See Attached documents for the complete upload flow.
Keep receipt state, quantity basis, and evidence quality together when deciding what has arrived. Document association records the evidence on the purchase order without changing its status or receiving inventory.