Skip to main content

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.

The atomic-create principle

The Arcus Products API accepts the complete nested resource graph in a single POST. You express what you want; the API creates every child in one atomic transaction. If any child fails, the entire request rolls back — no orphan products, no partial state.

product_type discriminator

Every product has a product_type that controls which children are valid:
product_typeWhat it isInline children accepted
physicalStandalone stockable itempricing[], vendors[]
serviceNon-stockable service linepricing[], vendors[]
kitBill-of-materials assemblycomponents[], pricing[], vendors[]
boxPackaging unit (also a kit)components[], pricing[], vendors[]
variant_parentParent with multiple variantsvariants[], each variant may include components[], pricing[], vendors[]

Full example: variant parent with kit variants

A “Riser Kit” with two kit variants — Dome and Flat — each with their own component assemblies, three qty-break pricing tiers, and a vendor assignment. One POST call.
curl -X POST https://api.arcuserp.com/v1/products \
  -H "Authorization: Bearer ark_live_ent_wss_abc123" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: riser-kit-2026-05-12-001" \
  -d '{
    "title": "Riser Kit",
    "product_type": "variant_parent",
    "description": "Modular riser kit with dome or flat options",
    "variants": [
      {
        "title": "Dome Riser Kit",
        "sku": "RISER-DOME",
        "product_type": "kit",
        "components": [
          {"component_product_id": "prod_stone_uuid", "quantity": 2},
          {"component_product_id": "prod_dome_lid_uuid", "quantity": 1}
        ],
        "pricing": [
          {"pricing_level_id": "pl_default_uuid", "min_quantity": 1,  "list_price": 49.99},
          {"pricing_level_id": "pl_default_uuid", "min_quantity": 5,  "list_price": 44.99},
          {"pricing_level_id": "pl_default_uuid", "min_quantity": 10, "list_price": 39.99}
        ],
        "vendors": [
          {"vendor_id": "acct_acme_uuid", "vendor_sku": "RD-001", "default_unit_cost": 18.00}
        ]
      },
      {
        "title": "Flat Riser Kit",
        "sku": "RISER-FLAT",
        "product_type": "kit",
        "components": [
          {"component_product_id": "prod_stone_uuid", "quantity": 2},
          {"component_product_id": "prod_flat_lid_uuid", "quantity": 1}
        ],
        "pricing": [
          {"pricing_level_id": "pl_default_uuid", "min_quantity": 1,  "list_price": 44.99},
          {"pricing_level_id": "pl_default_uuid", "min_quantity": 5,  "list_price": 39.99},
          {"pricing_level_id": "pl_default_uuid", "min_quantity": 10, "list_price": 34.99}
        ]
      }
    ],
    "vendors": [
      {"vendor_id": "acct_acme_uuid", "vendor_sku": "RISER-PARENT", "default_unit_cost": 15.00}
    ]
  }'
The response includes every child hydrated inline:
{
  "data": {
    "id": "prod_abc123",
    "title": "Riser Kit",
    "product_type": "variant_parent",
    "entity_id": "ent_wss_abc",
    "variants": [
      {
        "id": "pv_dome_uuid",
        "title": "Dome Riser Kit",
        "sku": "RISER-DOME",
        "components": [
          { "id": "kc_uuid1", "component_product_id": "prod_stone_uuid", "quantity_per_kit": 2 },
          { "id": "kc_uuid2", "component_product_id": "prod_dome_lid_uuid", "quantity_per_kit": 1 }
        ],
        "pricing": [
          { "id": "pp_uuid1", "pricing_level_id": "pl_default_uuid", "qty_break": 1,  "list_price": 49.99 },
          { "id": "pp_uuid2", "pricing_level_id": "pl_default_uuid", "qty_break": 5,  "list_price": 44.99 },
          { "id": "pp_uuid3", "pricing_level_id": "pl_default_uuid", "qty_break": 10, "list_price": 39.99 }
        ],
        "vendors": [
          { "id": "pv_uuid1", "vendor_id": "acct_acme_uuid", "vendor_sku": "RD-001", "default_unit_cost": 18.00 }
        ]
      }
    ],
    "vendors": [
      { "id": "pv_parent_uuid", "vendor_id": "acct_acme_uuid", "vendor_sku": "RISER-PARENT" }
    ]
  }
}

Qty-break pricing with pricing_level_id

Each pricing[] element defines one row in a tiered price book:
FieldRequiredDescription
pricing_level_idYes (or account_id)The pricing level this tier applies to. Use GET /v1/pricing-levels to list available levels.
account_idYes (or pricing_level_id)Account-specific override price instead of a level-based price.
min_quantityNoThe minimum order quantity that activates this tier. Defaults to 1. Each tier must have a unique min_quantity within the same pricing_level_id scope.
list_priceNoThe sell price at this tier.
sell_priceNoExplicit sell price (overrides list_price if both provided).
All money fields (list_price, sell_price, adjustment) are returned as JavaScript numbers (float), not strings.

Idempotency

Include Idempotency-Key: <your-unique-key> on every create call. Replaying the same key within 24 hours returns the original response without re-creating resources.
curl -X POST https://api.arcuserp.com/v1/products \
  -H "Idempotency-Key: order-import-batch-2026-05-12-row-42" \
  ...

Standalone kit (no variants)

curl -X POST https://api.arcuserp.com/v1/products \
  -H "Authorization: Bearer ark_live_ent_wss_abc123" \
  -d '{
    "title": "Dome Lid Assembly",
    "product_type": "kit",
    "sku": "DLA-001",
    "components": [
      {"component_product_id": "prod_dome_uuid", "quantity": 1},
      {"component_product_id": "prod_gasket_uuid", "quantity": 2}
    ],
    "pricing": [
      {"pricing_level_id": "pl_default_uuid", "min_quantity": 1, "list_price": 24.99}
    ]
  }'

Error handling

Validation errors return the exact param path so you know which field in which child failed:
{
  "error": "missing_required_field",
  "code": "missing_required_field",
  "type": "validation_error",
  "hint": "pricing_level_id or account_id is required for each pricing row.",
  "param": "variants[0].pricing[2].pricing_level_id"
}
Transactional rollback: if any child write fails, no rows are written. The response always reflects the full success or full failure state.

Adding pricing tiers to an existing product

Use POST /v1/products/{id}/pricing to add tiers incrementally after creation:
curl -X POST https://api.arcuserp.com/v1/products/prod_abc123/pricing \
  -H "Authorization: Bearer ark_live_ent_wss_abc123" \
  -d '{
    "pricing_level_id": "pl_wholesale_uuid",
    "min_quantity": 1,
    "list_price": 42.00
  }'