Add a line item to a purchase order
Add a line item to an existing purchase order. The PO must be in
draft or open status. If the PO is in draft and this is the
first item, the PO auto-transitions to open and a
purchase_order.sent event is emitted.
If a line for the same (product_id, variant_id) already exists on
the PO, the incoming quantity is merged onto the existing line
(de-dupe) rather than creating a duplicate row.
unit_cost is optional. When omitted, the canonical
findBestPurchasePolicy resolver applies the best purchase pricing
policy (effective-date filter + multiplier support). Kit products
are rejected (create POs per component instead). Variant-parent
products are rejected unless a specific variant_id is provided.
Rejected with 422 if the PO is pending_approval; withdraw and revise.
purchasing:writeAuthorizations
API key issued per entity via Settings > Developers > API Keys.
Each key carries scopes (e.g. orders:read, products:write).
Bearer token format: Authorization: Bearer ark_live_ent_Test keys use ark_test_ent_. Both are issued per entity
via Settings > Developers > API Keys.
Headers
Optional idempotency key for safe retries (Stripe-style).
255Path Parameters
Body
The product (SKU) to add. Cannot be a kit. If the product has variants, variant_id is also required.
Quantity ordered. Must be positive.
x >= 0.0001Optional variant of product_id.
Optional unit cost override. Omit to auto-apply best purchase-pricing policy.
Optional pricing policy id to lock against (for audit trail).
Optional sort order on the PO; defaults to 0.
Optional pointer at the exact product_vendors row this PO line is bound
to. Persisted on order_items.product_vendor_id so the PO PDF / receiving
/ vendor email surface the operator-chosen vendor-part deterministically
when a product has 2+ product_vendors rows for the same vendor.
Validated against this entity (product_vendors -> products.entity_id) AND
the line's (product_id, vendor_id); mismatched ids reject with 400
(invalid_product_vendor_id / product_vendor_product_mismatch /
product_vendor_vendor_mismatch). Omit to let the PO PDF fall back to the
deterministic LATERAL LIMIT 1 default-vendor-part pick.
Response
Line item added (or merged into existing line of same product+variant).
A line item on an order. Sub-resource of Order.
Multi-tenant scoping column (Layer 1 isolation). Set automatically
from the parent orders.entity_id and enforced by Postgres trigger
trg_order_items_entity_parity (P0-ENTITY-ID-CHILD-TABLES, 2026-05-18).
Cross-tenant writes are rejected at the database layer.
Canonical Arcus per-unit price column (matches order_items.sell_rate).
Public-API alias of sell_rate (Stripe/Shopify/QuickBooks convention). Always populated on read; equal to sell_rate. Set per NEW-GAP-API-V1-CALLER-UNIT-PRICE-SILENTLY-OVERRIDDEN 2026-05-17 closure.
Per-unit pricing-rule savings (list_price minus sell_rate, positive magnitude). Already baked into sell_rate (and therefore line_subtotal) per ASC 606 transaction-price pricing; surfaced for the gross-to-net bridge display, never re-subtracted.
Per-line allocated coupon/order-level discount (signed; negative for a discount). Reflected in line_subtotal.
Per-line, per-source adjustment breakdown from order_item_adjustments (the canonical SSOT). Each entry attributes a signed line_amount to a source (pricing_rule | order_adjustment | coupon | manual_line_override | return_refund_adjust | restocking_fee). Empty array for lines with no allocations (and on legacy orders predating the writer). Industry parity: Shopify Admin GraphQL LineItem.discountAllocations[].
For purchase_order document_type lines only: exact product_vendors
row this line is bound to (NEW-GAP-ORDER-ITEMS-PRODUCT-VENDOR-ID-PROVENANCE,
2026-05-14). NULL for legacy PO lines and all non-PO doc types; PDF
falls back to the deterministic default-vendor-part pick.

