Void a posted order
Authorization: requires orders:write API-key scope AND the per-user
orders.delete permission (SoD parity sweep 2026-05-16; the api-v1
wrapper used to gate on scope alone, which let any junior staff with a
orders:write API key bypass the role check the human-user path enforces).
Void is the heavier action than cancel: it reverses GL on partially
fulfilled orders too, so the per-user permission required is
orders.delete (NOT orders.edit). System-actor calls without an
identifiable principal are denied per AICPA SoC2 CC6.1. Idempotent via
Idempotency-Key.
Voids a sales order or invoice. Mirror of POST /orders/{id}/cancel with a
permissive fulfillment guard: voidOrder is the canonical handler for
reversing a partially-fulfilled or fulfilled order when an RMA is not the
right path (e.g. customer dispute, fraud, data entry error pre-shipment).
Voiding reverses every booked GL JE (FULFILLMENT / TAX / SHIPPING / DISCOUNT),
releases inventory reservations, voids Shippo labels carrier-side, voids the
AvaTax committed transaction, and auto-voids any uncaptured Stripe
PaymentIntents with cancel_reason='order_voided'.
The order must not be already voided, archived, fully fulfilled (use returns
instead), partially fulfilled (operator must void packages first), or have
active shipments. If the order has child drop-ship purchase orders or child
work orders auto-created on confirm via the forward cascade, the same atomic
cascade behavior as POST /orders/{id}/cancel applies:
- If any child drop-ship PO has received goods (purchase_receipts exist),
HTTP 409
dropship_po_received_blocks_so_void. - If any child drop-ship PO was sent to the vendor but has no receipts,
HTTP 409
dropship_po_sent_blocks_so_void. - If any child work order has status
completedorclosed, HTTP 409manufactured_wo_completed_blocks_so_void. - If any child work order has status
in_progress, HTTP 409manufactured_wo_in_progress_blocks_so_void. - If any open RMA exists against the order, HTTP 409
open_rma_blocks_void. - Otherwise (every child is in a cascade-eligible state), all child POs +
WOs cancel atomically inside the same transaction as the SO void.
The response surfaces
cascaded_drop_ship_pos[]andcascaded_work_orders[]listing each child auto-cancelled by the cascade.
Behavior, atomicity, and error codes are guaranteed mirrors of the cancel path (NEW-GAP-CANCEL-SALES-ORDER-ORPHANS-DROPSHIP-PO 2026-05-15 + NEW-GAP-INVERSE-CASCADE-AUDIT-SWEEP Phase A 2026-05-15). For the underlying invariants see docs/context/ERP-CORRECTNESS-RULES.md §E3c + §E3d.
Authorizations
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
Client-generated unique key for idempotent POST/PATCH/DELETE operations. Alias for the Idempotency parameter. Max 255 chars. On retry with the same key, the original response is returned without re-executing the operation. Keys expire after 24 hours.
255Path Parameters
Body
Response
Voided order. Response may include cascaded_drop_ship_pos[] listing
child drop-ship POs auto-cancelled by the cascade and
cascaded_work_orders[] listing child work orders auto-cancelled by
the cascade. Includes voided_payment_intents[] for any uncaptured
Stripe PIs auto-voided post-commit (AUDIT-077b-G4) and void_failures[]
for any post-commit non-blocking failures (Shopify sync, AvaTax void).
An Arcus ERP order document. One table holds quotes, sales_orders, invoices, returns, and purchase_orders -- always filter by document_type. entity_id is always from the API key (Layer 1 isolation).
order quote, sales_order, invoice, return, purchase_order draft, confirmed, partially_fulfilled, fulfilled, cancelled, voided, awaiting_ach_clearance, on_hold unpaid, partially_paid, paid, overpaid, refunded, partially_refunded, voided unfulfilled, partially_fulfilled, fulfilled Derived (display-only): SUM(list_price * qty) over non-kit lines. The gross baseline of the gross-to-net bridge (List price minus pricing_savings equals subtotal). Never part of order_total.
Derived (display-only): SUM(pricing_rule_adjustment * qty) over non-kit lines (positive magnitude). Per-unit pricing-rule savings already baked into subtotal via sell_rate (ASC 606 transaction price); shown as an informational List-to-Subtotal bridge, never subtracted from order_total.
SSOT: utils/ar-helpers.mjs::updateARBalance. Do not write directly.
ship, pick_up, local_delivery order, manual, proforma, correction 
