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

# Create purchase order

> Creates a new purchase order in DRAFT status, optionally with initial lines. Returns 201 on creation, 200 when idempotency_key matched an existing PO.

<ParamField header="x-api-key" type="string" required>
  API key with `inventory:write` scope.
</ParamField>

<ParamField path="vendorId" type="string" required>
  Vendor UUID.
</ParamField>

<ParamField body="store_id" type="string">
  UUID of the receiving store. Exactly one of `store_id`, `external_store_id`, or `store_tax_id` must be provided.
</ParamField>

<ParamField body="external_store_id" type="string">
  Resolve the store by the cross-system external identifier. Mutually exclusive with `store_id` and `store_tax_id`.
</ParamField>

<ParamField body="store_tax_id" type="string">
  Resolve the store by its fiscal identifier (RUC, CNPJ, CUIT, NIT, RUT, RFC…). Returns `422` if multiple active stores share the same value — use `store_id` or `external_store_id` to disambiguate. Mutually exclusive with `store_id` and `external_store_id`.
</ParamField>

<ParamField body="supplier_id" type="string">
  UUID of the supplier. Exactly one of `supplier_id` or `external_supplier_id` must be provided.
</ParamField>

<ParamField body="external_supplier_id" type="string">
  External supplier identifier (e.g. RUC / tax id), resolved server-side. Mutually exclusive with `supplier_id`.
</ParamField>

<ParamField body="schedule_id" type="string">
  UUID of the receiving schedule this PO belongs to (optional).
</ParamField>

<ParamField body="order_type" type="string">
  Free-form order classification (max 64 chars).
</ParamField>

<ParamField body="cutoff_at" type="string">
  ISO 8601 timestamp of the order cutoff.
</ParamField>

<ParamField body="expected_delivery_at" type="string">
  ISO 8601 timestamp of the expected delivery.
</ParamField>

<ParamField body="notes" type="string">
  Free-text notes (max 1024 chars).
</ParamField>

<ParamField body="metadata" type="object">
  Free-form extra data.
</ParamField>

<ParamField body="idempotency_key" type="string">
  Client-supplied key (max 255 chars). Repeating the same key returns the existing PO with HTTP 200 instead of creating a duplicate. Recommended: one UUID v4 per business operation.
</ParamField>

<ParamField body="external_reference" type="string">
  Client-supplied document reference (e.g. an ERP movement code, max 256 chars). Stored for lookup and display, filterable on the list endpoint. Not a deduplication key — use `idempotency_key` for that.
</ParamField>

<ParamField body="external_user_id" type="string">
  Caller's user identifier for the audit trail. Optional on creation; required on `close`.
</ParamField>

<ParamField body="enforce_supplier_catalog" type="boolean">
  When `true`, every line item must exist in the supplier's catalog.
</ParamField>

<ParamField body="lines" type="object[]">
  Initial order lines (optional — you can add them later with `action=add-lines`):

  <Expandable title="line fields">
    <ParamField body="item_id" type="string">UUID of the item. Exactly one of `item_id`, `external_item_id`, or `supplier_sku` must be provided.</ParamField>
    <ParamField body="external_item_id" type="string">External item id, resolved server-side. When used, `base_unit_id` becomes optional.</ParamField>
    <ParamField body="supplier_sku" type="string">Supplier SKU (case-insensitive, max 128 chars). Resolved to the matching item in the order's supplier catalog. `base_unit_id` is also derived automatically.</ParamField>
    <ParamField body="qty" type="number" required>Ordered quantity in the entry unit.</ParamField>
    <ParamField body="qty_base" type="number">Ordered quantity in the item's base unit. Required unless `unit_code` or `item_unit_id` is provided — in both cases the server derives it as `qty × factor_to_base`. If you send it anyway, it must match the derived value (tolerance 0.001) or the request fails with `purchase_order_qty_base_mismatch` (422).</ParamField>
    <ParamField body="base_unit_id" type="string">UUID of the base unit. Required unless `external_item_id` or `supplier_sku` is used.</ParamField>
    <ParamField body="unit_to_base_factor" type="number">Conversion factor from the entry unit to base.</ParamField>
    <ParamField body="item_unit_id" type="string">UUID of an existing item unit. The server derives `qty_base` from the unit's `factor_to_base` — you don't need to know the conversion factor. Returns `item_unit_not_found` (404) if the unit doesn't resolve and `qty_base` was omitted. Mutually exclusive with `unit_code` and `unit_label`.</ParamField>
    <ParamField body="unit_code" type="string">Resolve the purchase unit by its integration code (case-insensitive). Mutually exclusive with `item_unit_id` and `unit_label`.</ParamField>
    <ParamField body="unit_label" type="string">Free-form unit label (e.g. `"costal"`), stored when `item_unit_id` is absent.</ParamField>
    <ParamField body="save_unit" type="boolean">When `true` and `unit_label` is set, saves a new PURCHASE unit on the item for future reuse.</ParamField>
    <ParamField body="unit_cost" type="number">Cost per unit (≥ 0).</ParamField>
    <ParamField body="tax_amount" type="number">Informational: tax amount for the line.</ParamField>
    <ParamField body="delivery_amount" type="number">Informational: delivery / freight amount.</ParamField>
    <ParamField body="total_amount" type="number">Informational: declared total amount.</ParamField>
    <ParamField body="markup_amount" type="number">Informational: commission / markup amount.</ParamField>
    <ParamField body="notes" type="string">Line notes (max 512 chars).</ParamField>
    <ParamField body="metadata" type="object">Extra data per line.</ParamField>
  </Expandable>
</ParamField>

<ResponseField name="purchase_order" type="object">
  The full purchase order detail: identifiers, `status`, lifecycle timestamps (`submitted_at`, `confirmed_at`, `cancelled_at`, `closed_at`), actor fields, and `lines[]`.
</ResponseField>

<RequestExample>
  ```json Using internal UUIDs theme={null}
  {
    "supplier_id": "sup_best_foods_01...",
    "store_id": "str_main_01...",
    "expected_delivery_at": "2026-08-14T10:00:00-05:00",
    "notes": "Weekly protein order",
    "idempotency_key": "0d4f1c9a-7c33-4d6e-9f2a-1b8e5a6c0d21",
    "lines": [
      {
        "item_id": "itm_chicken_01...",
        "qty": 10,
        "qty_base": 10000,
        "base_unit_id": "unit_g_01...",
        "unit_to_base_factor": 1000,
        "unit_label": "kg",
        "unit_cost": 4.5
      }
    ]
  }
  ```

  ```json Using external identifiers (ERP integration) theme={null}
  {
    "external_supplier_id": "RUC-001234567",
    "store_id": "str_main_01...",
    "external_reference": "MOV-2026-00342",
    "idempotency_key": "0d4f1c9a-7c33-4d6e-9f2a-1b8e5a6c0d21",
    "lines": [
      {
        "external_item_id": "SAL-GRUESA-001",
        "qty": 5,
        "unit_code": "COSTAL-SAL",
        "tax_amount": 2.5,
        "total_amount": 27.5
      }
    ]
  }
  ```

  ```json Using supplier SKUs theme={null}
  {
    "external_supplier_id": "RUC-001234567",
    "store_id": "str_main_01...",
    "external_reference": "MOV-2026-00342",
    "lines": [
      {
        "supplier_sku": "SKU-CHICKEN-001",
        "qty": 10,
        "unit_code": "kg",
        "total_amount": 55.0
      }
    ]
  }
  ```

  ```json Fully external (no internal UUIDs) theme={null}
  {
    "external_supplier_id": "RUC-001234567",
    "store_tax_id": "0991234560001",
    "external_reference": "MOV-2026-00342",
    "external_user_id": "erp-user-42",
    "lines": [
      {
        "supplier_sku": "SKU-CHICKEN-001",
        "qty": 10,
        "unit_code": "kg",
        "total_amount": 55.0
      }
    ]
  }
  ```
</RequestExample>

<ResponseExample>
  ```json 201 theme={null}
  {
    "purchase_order": {
      "id": "po_01j5k...",
      "account_id": "acc_01...",
      "vendor_id": "vnd_01...",
      "supplier_id": "sup_best_foods_01...",
      "store_id": "str_main_01...",
      "status": "DRAFT",
      "expected_delivery_at": "2026-08-14T15:00:00.000Z",
      "submitted_at": null,
      "confirmed_at": null,
      "cancelled_at": null,
      "closed_at": null,
      "external_reference": null,
      "notes": "Weekly protein order",
      "metadata": {},
      "created_at": "2026-08-11T12:00:00.000Z",
      "updated_at": "2026-08-11T12:00:00.000Z",
      "lines": [
        {
          "id": "pol_01...",
          "item_id": "itm_chicken_01...",
          "qty": 10,
          "qty_base": 10000,
          "base_unit_id": "unit_g_01...",
          "unit_to_base_factor": 1000,
          "unit_label": "kg",
          "unit_cost": 4.5
        }
      ]
    }
  }
  ```

  ```json 404 (supplier not found by external id) theme={null}
  {
    "error": {
      "kind": "purchase_order_supplier_external_id_not_found",
      "message": "No supplier matches the provided external_supplier_id"
    }
  }
  ```

  ```json 404 (item external id not found) theme={null}
  {
    "error": {
      "kind": "purchase_order_item_external_id_not_found",
      "message": "One or more external_item_id values could not be resolved",
      "details": { "external_item_ids": ["SAL-UNKNOWN-001"] }
    }
  }
  ```

  ```json 404 (store external id not found) theme={null}
  {
    "error": {
      "kind": "purchase_order_store_external_id_not_found",
      "message": "No active store matches the provided external_store_id"
    }
  }
  ```

  ```json 404 (store tax id not found) theme={null}
  {
    "error": {
      "kind": "purchase_order_store_tax_id_not_found",
      "message": "No active store matches the provided store_tax_id"
    }
  }
  ```

  ```json 422 (store tax id ambiguous) theme={null}
  {
    "error": {
      "kind": "purchase_order_store_tax_id_ambiguous",
      "message": "Multiple active stores share the same tax_id — use store_id or external_store_id to disambiguate",
      "details": { "tax_id": "0991234560001", "count": 3 }
    }
  }
  ```

  ```json 422 (qty_base mismatch) theme={null}
  {
    "error": {
      "kind": "purchase_order_qty_base_mismatch",
      "message": "Client-provided qty_base does not match the server-derived value"
    }
  }
  ```

  ```json 404 (item unit not found) theme={null}
  {
    "error": {
      "kind": "item_unit_not_found",
      "message": "item_unit_id does not resolve to an active unit and qty_base was omitted"
    }
  }
  ```
</ResponseExample>
