> ## Documentation Index
> Fetch the complete documentation index at: https://docs.arcuserp.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Create an order (any document_type)

> Atomic order create. A single POST creates the order header plus all inline
children in one transactional write. Any child failure rolls back the entire
graph -- no half-baked orders.

**Inline children accepted:**

- `line_items[]` -- each entry specifies `product_id`, `quantity`, and optionally
  `variant_id` or `sell_rate` (override). Pricing engine runs per-item (qty-break
  pricing levels, account defaults). Variant guard: if the product has variants,
  `variant_id` is required.
- `discount` -- header-level discount applied as an order_adjustment row.
  `{type: "percentage"|"flat", value: number}`. Percentage is applied to the sum
  of line subtotals before tax.
- `auto_compute_tax: true` -- triggers AvaTax (or local rate) after all items are
  inserted. Requires a `shipping_address_id` (or inline `shipping_address`) that
  resolves to a US jurisdiction. Skips cleanly for tax-exempt accounts.
- `auto_allocate_inventory: true` -- reserves stock per line item at `location_id`
  (falls back to entity default location). Returns `422 insufficient_inventory`
  with shortfall details if any line lacks available stock. The rollback is atomic:
  no line is reserved if any line fails.
- `payments[]` -- inline charge after the order and items are committed. Each entry:
  `{payment_method_id, amount, payment_type?, auto_capture?}`. `payment_method_id`
  is the Arcus internal UUID from `account_payment_methods`. Payment failure does
  NOT roll back the order (industry standard -- order persists with
  `payment_status: unpaid`; retry via `POST /v1/orders/{id}/payments`).
  Results appear in `_inline_payment_results[]` in the response.

**Response:** fully hydrated order with `line_items`, `payments`, and `tax_lines`
expanded. Developer never needs a follow-up GET.

**Totals guarantee (NEW-GAP Wave A.5, 2026-05-15):** the response order
always lands with non-NULL `subtotal`, `tax_total`, `shipping_total`,
and `order_total` -- the canonical totals helper runs inside the
same transaction as the order + line-item INSERTs, so a successful
201 implies the header has been recomputed against the just-inserted
items. Tax + shipping totals are 0 when no AvaTax connector is active
or the shipping address is incomplete (a `warning` is logged but never
leaks into the response envelope).

**Idempotency:** supply `Idempotency-Key` header to safely retry without
double-creating. The same key returns the same response.

See the [Creating Orders guide](https://arcuserp.mintlify.app/guides/creating-orders)
for curl, TypeScript, and Python examples.




## OpenAPI

````yaml /openapi.yaml post /orders
openapi: 3.1.0
info:
  title: Arcus ERP Public API
  version: 1.0.0
  description: >
    Arcus ERP public REST API. Designed for external integrations and data
    migration.


    **Authentication.** Bearer token (API key) via the `Authorization` header.

    Format: `Authorization: Bearer ark_live_ent_<code>_<random>` (or
    `ark_test_*` for sandbox).

    API keys are issued per-entity in **Settings > Developers > API Keys**.


    **Entity scoping.** The entity is encoded in the API key prefix; routes are
    flat

    (e.g. `/v1/accounts`, `/v1/orders`, `/v1/products`). A small set of platform
    endpoints

    (migration, reconciliation, events, webhook endpoints, API keys) use the

    `/v1/entities/{entity_id}/...` form -- those are noted in their tags.


    **Key capabilities.**
      - Related-resource hydration via `?expand[]=` (see `x-arcus-expand` on each resource).
      - Cursor-based pagination (`starting_after` / `ending_before` / `limit`).
      - Idempotency via the `Idempotency-Key` header.
      - Webhook events for asynchronous notification.
      - Conditional requests / ETag for cache validation.
servers:
  - url: https://api.arcuserp.com/v1
    description: Arcus ERP API (accepts both live `ark_live_*` and test `ark_test_*` keys)
  - url: https://dev-api.arcuserp.com/v1
    description: >-
      Dev sandbox API (test-only data, accepts `ark_test_*` keys against dev
      RDS)
security: []
paths:
  /orders:
    post:
      tags:
        - Orders
      summary: Create an order (any document_type)
      description: >
        Atomic order create. A single POST creates the order header plus all
        inline

        children in one transactional write. Any child failure rolls back the
        entire

        graph -- no half-baked orders.


        **Inline children accepted:**


        - `line_items[]` -- each entry specifies `product_id`, `quantity`, and
        optionally
          `variant_id` or `sell_rate` (override). Pricing engine runs per-item (qty-break
          pricing levels, account defaults). Variant guard: if the product has variants,
          `variant_id` is required.
        - `discount` -- header-level discount applied as an order_adjustment
        row.
          `{type: "percentage"|"flat", value: number}`. Percentage is applied to the sum
          of line subtotals before tax.
        - `auto_compute_tax: true` -- triggers AvaTax (or local rate) after all
        items are
          inserted. Requires a `shipping_address_id` (or inline `shipping_address`) that
          resolves to a US jurisdiction. Skips cleanly for tax-exempt accounts.
        - `auto_allocate_inventory: true` -- reserves stock per line item at
        `location_id`
          (falls back to entity default location). Returns `422 insufficient_inventory`
          with shortfall details if any line lacks available stock. The rollback is atomic:
          no line is reserved if any line fails.
        - `payments[]` -- inline charge after the order and items are committed.
        Each entry:
          `{payment_method_id, amount, payment_type?, auto_capture?}`. `payment_method_id`
          is the Arcus internal UUID from `account_payment_methods`. Payment failure does
          NOT roll back the order (industry standard -- order persists with
          `payment_status: unpaid`; retry via `POST /v1/orders/{id}/payments`).
          Results appear in `_inline_payment_results[]` in the response.

        **Response:** fully hydrated order with `line_items`, `payments`, and
        `tax_lines`

        expanded. Developer never needs a follow-up GET.


        **Totals guarantee (NEW-GAP Wave A.5, 2026-05-15):** the response order

        always lands with non-NULL `subtotal`, `tax_total`, `shipping_total`,

        and `order_total` -- the canonical totals helper runs inside the

        same transaction as the order + line-item INSERTs, so a successful

        201 implies the header has been recomputed against the just-inserted

        items. Tax + shipping totals are 0 when no AvaTax connector is active

        or the shipping address is incomplete (a `warning` is logged but never

        leaks into the response envelope).


        **Idempotency:** supply `Idempotency-Key` header to safely retry without

        double-creating. The same key returns the same response.


        See the [Creating Orders
        guide](https://arcuserp.mintlify.app/guides/creating-orders)

        for curl, TypeScript, and Python examples.
      operationId: createOrder
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - document_type
                - account_id
              properties:
                document_type:
                  type: string
                  enum:
                    - quote
                    - sales_order
                    - invoice
                    - return
                    - purchase_order
                  description: >-
                    Discriminator. sales_order and invoice are for customer
                    accounts; purchase_order for vendors.
                account_id:
                  type: string
                  format: uuid
                  description: >-
                    Customer or vendor account. Account defaults (pricing level,
                    addresses, payment terms) are auto-inherited.
                location_id:
                  type: string
                  format: uuid
                  description: >-
                    Warehouse location for inventory allocation. Defaults to
                    entity default location.
                shipping_address_id:
                  type: string
                  format: uuid
                  description: >-
                    Shipping address. Auto-resolved from account default when
                    omitted.
                billing_address_id:
                  type: string
                  format: uuid
                  description: >-
                    Billing address. Auto-resolved from account default when
                    omitted.
                payment_term_id:
                  type: string
                  format: uuid
                  description: >-
                    Payment terms (e.g. Net 30). Auto-resolved from account,
                    channel, and entity default cascade.
                sales_channel_id:
                  type: string
                  format: uuid
                pricing_level_id:
                  type: string
                  format: uuid
                  description: >-
                    Override pricing level. Auto-resolved from account default
                    when omitted.
                po_number:
                  type: string
                  description: Customer purchase order number.
                order_date:
                  type: string
                  format: date-time
                  description: Order date. Defaults to now.
                notes:
                  type: string
                  description: Customer-visible notes.
                internal_notes:
                  type: string
                  description: Internal-only notes.
                customer_notes:
                  type: string
                requested_ship_date:
                  type: string
                  format: date
                ship_complete:
                  type: boolean
                  description: >-
                    When true, do not ship partial. Inherited from account
                    default.
                ships_freight:
                  type: boolean
                tax_exempt:
                  type: boolean
                  description: >-
                    Mark order tax-exempt. Requires avatax_entity_code on the
                    order or linked account.
                avatax_entity_code:
                  type: string
                  description: AvaTax exemption entity code (e.g. 'RESALE', 'EXEMPT').
                sales_agent_id:
                  type: string
                  format: uuid
                metadata:
                  type: object
                  description: Arbitrary key-value metadata stored on the order.
                line_items:
                  type: array
                  description: >-
                    Inline line items. Inserted atomically with the order. Any
                    failure rolls back all items and the order header.
                  items:
                    type: object
                    required:
                      - product_id
                      - quantity
                    properties:
                      product_id:
                        type: string
                        format: uuid
                      variant_id:
                        type: string
                        format: uuid
                        description: Required when the product has variants.
                      quantity:
                        type: number
                        description: Quantity. Must be > 0.
                      sell_rate:
                        type: number
                        description: >-
                          Override unit price (canonical Arcus field). Omit to
                          use pricing engine (qty-break + level defaults).
                      unit_price:
                        type: number
                        description: >-
                          Alias for sell_rate (Stripe/Shopify convention).
                          Either name accepted; supplying both with different
                          values returns 400 price_field_conflict. Negative or
                          zero returns 422 invalid_price. When applied price
                          differs from catalog list_price, response carries
                          warnings array entries (code price_override,
                          catalog_price, applied_price, delta) plus one
                          order.price_override audit_log row per overridden
                          line.
                          NEW-GAP-API-V1-CALLER-UNIT-PRICE-SILENTLY-OVERRIDDEN
                          closure 2026-05-17.
                      notes:
                        type: string
                discount:
                  type: object
                  description: Header-level discount applied to the order subtotal.
                  properties:
                    type:
                      type: string
                      enum:
                        - percentage
                        - flat
                    value:
                      type: number
                      description: Percentage (0-100) or flat dollar amount.
                auto_compute_tax:
                  type: boolean
                  description: >-
                    Run AvaTax (or local rate) after all items are inserted.
                    Requires shipping_address_id to resolve to a taxable
                    jurisdiction.
                auto_allocate_inventory:
                  type: boolean
                  description: >-
                    Reserve inventory per line item. Returns 422 with shortfall
                    details if any line has insufficient stock. Rollback is
                    atomic.
                payments:
                  type: array
                  description: >-
                    Inline payment(s). Fired after the order is committed.
                    Payment failure does NOT roll back the order.
                  items:
                    type: object
                    required:
                      - payment_method_id
                      - amount
                    properties:
                      payment_method_id:
                        type: string
                        format: uuid
                        description: Arcus internal UUID from account_payment_methods.
                      amount:
                        type: number
                        description: Amount to charge in USD.
                      payment_type:
                        type: string
                        enum:
                          - card
                          - ach
                          - cash
                          - check
                          - credit
                          - terms
                          - external
                        default: card
                      auto_capture:
                        type: boolean
                        default: true
                      save_card:
                        type: boolean
                        description: Attach card to account for future off-session use.
            example:
              document_type: sales_order
              account_id: c3f2a7b1-0e44-4f89-9d12-aabb0c123456
              location_id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
              shipping_address_id: d4e5f6a7-b8c9-0123-def4-567890abcdef
              billing_address_id: e5f6a7b8-c9d0-1234-ef56-7890abcdef01
              shipping_method: ups_ground
              line_items:
                - product_id: 11111111-2222-3333-4444-555555555555
                  quantity: 5
                - product_id: 22222222-3333-4444-5555-666666666666
                  quantity: 3
                - product_id: 33333333-4444-5555-6666-777777777777
                  variant_id: 44444444-5555-6666-7777-888888888888
                  quantity: 10
              discount:
                type: percentage
                value: 5
              auto_compute_tax: true
              auto_allocate_inventory: true
              payments:
                - payment_method_id: 55555555-6666-7777-8888-999999999999
                  amount: 750
                  payment_type: card
                  auto_capture: true
      responses:
        '201':
          description: Created order (hydrated with line_items, payments, tax_lines)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '400':
          $ref: '#/components/responses/Error'
        '401':
          $ref: '#/components/responses/Error'
        '403':
          $ref: '#/components/responses/Error'
        '409':
          $ref: '#/components/responses/Error'
        '422':
          $ref: '#/components/responses/Error'
      security:
        - ApiKeyAuth: []
components:
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      description: |
        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.
      schema:
        type: string
        maxLength: 255
  schemas:
    Order:
      type: object
      description: >
        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).
      properties:
        id:
          type: string
          format: uuid
        object:
          type: string
          enum:
            - order
        entity_id:
          type: string
          format: uuid
          readOnly: true
        order_number:
          type: string
          readOnly: true
        document_type:
          type: string
          enum:
            - quote
            - sales_order
            - invoice
            - return
            - purchase_order
        order_status:
          type: string
          enum:
            - draft
            - confirmed
            - partially_fulfilled
            - fulfilled
            - cancelled
            - voided
            - awaiting_ach_clearance
            - on_hold
        payment_status:
          type: string
          enum:
            - unpaid
            - partially_paid
            - paid
            - overpaid
            - refunded
            - partially_refunded
            - voided
        fulfillment_status:
          type: string
          enum:
            - unfulfilled
            - partially_fulfilled
            - fulfilled
        account_id:
          type: string
          format: uuid
          nullable: true
        location_id:
          type: string
          format: uuid
          nullable: true
        po_number:
          type: string
          nullable: true
        order_date:
          type: string
          format: date-time
          nullable: true
        due_date:
          type: string
          format: date-time
          nullable: true
        subtotal:
          type: number
        discount_total:
          type: number
        shipping_total:
          type: number
        tax_total:
          type: number
        fee_total:
          type: number
        order_total:
          type: number
        list_price_total:
          type: number
          readOnly: true
          description: >-
            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.
        pricing_savings:
          type: number
          readOnly: true
          description: >-
            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.
        amount_paid:
          type: number
          readOnly: true
          description: 'SSOT: utils/ar-helpers.mjs::updateARBalance. Do not write directly.'
        balance_due:
          type: number
          readOnly: true
        tax_exempt:
          type: boolean
        delivery_option:
          type: string
          enum:
            - ship
            - pick_up
            - local_delivery
        notes:
          type: string
          nullable: true
        internal_notes:
          type: string
          nullable: true
        invoice_number:
          type: string
          nullable: true
          readOnly: true
        invoice_type:
          type: string
          enum:
            - order
            - manual
            - proforma
            - correction
          nullable: true
        is_on_hold:
          type: boolean
          readOnly: true
        hold_type:
          type: string
          nullable: true
          readOnly: true
        ship_complete:
          type: boolean
        source_platform:
          type: string
          nullable: true
        external_order_id:
          type: string
          nullable: true
        external_order_number:
          type: string
          nullable: true
        metadata:
          type: object
          nullable: true
        created_at:
          type: string
          format: date-time
          readOnly: true
        updated_at:
          type: string
          format: date-time
          readOnly: true
    ErrorEnvelope:
      type: object
      description: |
        Canonical error response envelope. All API errors use this shape.
      required:
        - error
        - code
      properties:
        error:
          type: string
          description: Machine-readable error key
          example: not_found
        code:
          type: string
          description: Machine-readable error code (often same as error)
          example: not_found
        type:
          type: string
          enum:
            - validation_error
            - permission_error
            - not_found
            - conflict
            - rate_limit
            - internal
            - expand_error
            - not_implemented
          example: not_found
        hint:
          type: string
          description: Human-readable one-sentence explanation (English)
          example: >-
            The requested order does not exist or does not belong to this
            entity.
        param:
          type: string
          description: The parameter that caused the error, if applicable
          example: expand[0]
        required:
          type: string
          description: The scope required (only on insufficient_scope errors)
          example: accounts:read
        request_id:
          type: string
          description: >-
            Unique request ID for support tracing (maps to CloudWatch log
            stream)
          example: req_abc123
  responses:
    Error:
      description: Error response (400/401/403/404/409/422/429/500)
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
  securitySchemes:
    ApiKeyAuth:
      type: http
      scheme: bearer
      description: |
        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_<code>_<random>
        Test keys use ark_test_ent_<code>_<random>. Both are issued per entity
        via Settings > Developers > API Keys.

````