Overview
POST /v1/orders is the atomic create endpoint for all order document types (quotes, sales orders, invoices, purchase orders, and returns). A single request can create the order header plus all inline children:
- Line items with automatic pricing (qty-break levels, account defaults)
- Header-level discount (percentage or flat)
- Automatic tax via AvaTax or local rates
- Inventory allocation per line item
- Inline payment charged after commit
line_items, payments, and tax_lines expanded inline. You never need a follow-up GET to see what was created.
Canonical scenario: 3 line items + discount + tax + allocation + payment
Document types
document_type | Use for | Account type |
|---|---|---|
quote | Non-binding estimate | Customer |
sales_order | Standard order (confirm to allocate) | Customer |
invoice | Billable invoice (auto-posts to AR) | Customer |
return | Return merchandise authorization | Customer |
purchase_order | Purchase from a vendor | Vendor |
Auto-populate from account defaults
When you provide anaccount_id, Arcus auto-resolves:
- Shipping and billing address from
is_default_shipping/is_default_billingflags - Pricing level from
accounts.default_pricing_level_id - Payment terms from account, then channel, then entity-level default
- Sales channel from
accounts.default_sales_channel_id - Tax exemption from
accounts.tax_exemptandaccounts.avatax_entity_code
{document_type, account_id}.
Line items
- Pricing engine runs automatically: qty-break pricing levels, account default pricing level.
Override with
sell_rate. - Variant guard: if the product has variants,
variant_idis required. Otherwise the request returns422 validation_errorwithparam: "line_items[N].variant_id". - Kit expansion: kit products automatically expand their components as child line items (zero-dollar children). No additional calls needed.
- Any child failure rolls back all items and the order header. Nothing is persisted on validation error.
Discount
| Type | Behavior |
|---|---|
percentage | Applied to line item subtotal sum (before tax). value = 0-100. |
flat | Fixed dollar amount deducted from subtotal. |
order_adjustment row with adjustment_type: 'discount'.
Automatic tax (auto_compute_tax)
true, Arcus calls AvaTax (or local tax rates if AvaTax is not configured) after all
items are inserted. Results appear in tax_lines[] and tax_total in the response.
Requirements:
shipping_address_idmust resolve to a taxable US jurisdiction.- Tax-exempt accounts (with
avatax_entity_code) are auto-detected andtax_totalwill be 0.
tax_total defaults to 0. You can trigger a re-calculation later via POST /v1/orders/{id}/recalculate.
Inventory allocation (auto_allocate_inventory)
true, Arcus reserves stock per line item via ORDER_RESERVATION inventory transactions.
- Location: uses
location_idfrom the request, or entity default location. - Shortfall guard: if ANY line item has insufficient
availablestock, the entire request returns422 insufficient_inventorywith per-product shortfall details. The rollback is atomic — nothing is allocated if any line fails. - Release: inventory is automatically released on order cancel or void.
Example shortfall response
Inline payments (payments[])
payment_method_id is the Arcus internal UUID from account_payment_methods (not the Stripe pm_xxx ID).
Use GET /v1/accounts/{id}/payment-methods to list available methods.
Payment fires after the order is committed to the database. This matches industry behavior:
if the payment fails, the order still exists with payment_status: unpaid. Retry the payment via
POST /v1/orders/{id}/payments.
Inline payment results appear in _inline_payment_results[] alongside the main response.
Idempotency
Include theIdempotency-Key header to safely retry without double-creating the order.
The same key returns the same response (including the same order number) without
re-running any DB writes or Stripe charges.
GL behavior
No GL entries fire at order create. The general ledger is only affected at:- Fulfillment: COGS debit, inventory credit
- Payment: AR debit, cash/revenue credit
Webhook events
Subscribers onorder.created receive this event immediately after the order is committed.
If inline payments succeed, payment.received fires as well. See Webhooks
for event schemas and retry policy.
Error reference
| Code | HTTP | Meaning |
|---|---|---|
missing_field | 400 | Required top-level field missing (document_type, account_id) |
validation_failed | 400 | Inline child validation failure (see param for exact path) |
line_item_failed | 400 | A specific line item was rejected (inactive product, box type, etc.) |
insufficient_inventory | 422 | auto_allocate_inventory shortfall — see product_id, requested, available |
account_role_mismatch | 422 | Sales order against a vendor account (or PO against a customer account) |
tax_exempt_requires_exemption_code | 422 | tax_exempt: true but no avatax_entity_code on order or account |
payment_method_not_found | 404 | Inline payment_method_id UUID does not exist for this entity |
insufficient_scope | 403 | API key lacks orders:write scope |

