---
title: "Bulk create or update purchase orders"
method: POST
path: "/purchase-orders/bulk"
tags: ["purchaseOrders"]
---

# Bulk create or update purchase orders

`POST /purchase-orders/bulk`

Creates or updates multiple purchase orders in a single request. Maximum 100 purchase orders and 1000 total line items per request. Processing is always asynchronous via Celery and returns a batch tracking ID for polling progress.

## Headers

- `Authorization` string, required
- `X-Api-Key` string, required
- `X-API-Version` string
- `Idempotency-Key` string

## Request body

- PurchaseOrderBulkUpsertRequest
  - `ottimate_company_id` integer, required — Company ID for all purchase orders in this batch
  - `ottimate_location_id` integer, required — Default location ID for all purchase orders in this batch
  - `purchase_orders` PurchaseOrderBulkUpsertRequestPurchaseOrdersItems[], required — Max 100 POs with max 1000 total items
    - `external_id` string
    - `po_number` string, required
    - `erp_vendor_id` string, required — External vendor identifier from ERP system
    - `erp_vendor_name` string — Vendor name from ERP system
    - `date` string, date, required
    - `total_amount` number, double, required
    - `tax` number, double
    - `freight` number, double
    - `miscellaneous_charges` number, double
    - `invoice_number_ref` string — Invoice reference number
    - `is_2_way` boolean — Whether this is a 2-way match PO
    - `items` PurchaseOrderBulkUpsertRequestPurchaseOrdersItemsItemsItems[], required
      - `external_id` string
      - `name` string, required
      - `sku` string
      - `quantity` number, double, required
      - `price` number, double, required
      - `uom` string
      - `dimensions` PurchaseOrderBulkUpsertRequestPurchaseOrdersItemsItemsItemsDimensions — Dimension values keyed by type (e.g. PROJECT, CLASS). Each value is the ERP external_id of the dimension. When provided, REPLACES all existing dimensions on the item — include every dimension you want to keep. Omit the field or pass null to leave dimensions unchanged. Passing {} returns 400.
    - `custom_fields` PurchaseOrderBulkUpsertRequestPurchaseOrdersItemsCustomFields — Optional custom fields configured for this company's purchase orders. Provide field values, pass null, or omit the field entirely — passing {} (empty object) returns 400.

## Response `202`

Asynchronous processing started. Poll batch_url for progress.

- BulkUpsertAsyncResponse
  - `version` string
  - `status` 'processing', required
  - `batch_id` string, required
  - `batch_url` string
  - `results_url` string
  - `summary` BulkUpsertAsyncResponseSummary
    - `count` integer
    - `total_items` integer

## Other responses

- `400` — Bad request - Invalid parameters or request format
- `403` — Forbidden - Access denied or insufficient permissions

## Changes

- **2026-08-22** `75aab60eedc9` — 2 breaking, 1 warning
  - for the `header` request parameter `Idempotency-Key`, the minLength was increased from `0` to `1`
  - added the pattern `^[A-Za-z0-9._\-+=/]{1,128}$` to the `header` request parameter `Idempotency-Key`
  - for the `header` request parameter `Idempotency-Key`, the maxLength was set to `128`
- **2026-08-19** `c0b5cf6c7a72` — 1 info
  - added the non-success response with the status `403`
- **2026-08-17** `c231509a03cf` — 1 breaking, 2 info
  - the `message` response's property type/format changed from `string`/`` to ``/`` for status `400`
  - the response property `code` became required for the status `400`
  - the response property `message` became required for the status `400`
- **2026-08-13** `1f089f3e34d9` — 3 breaking
  - the response property `code` became optional for the status `400`
  - the response property `message` became optional for the status `400`
  - the `message` response's property type/format changed from ``/`` to `string`/`` for status `400`

[Change history](https://skmtc.dev/ottimate/apis/api-reference/changes/purchase-orders/bulk/post.md)

---

[API](https://skmtc.dev/ottimate/apis/api-reference.md) · [All operations](https://skmtc.dev/ottimate/apis/api-reference/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/ottimate/api-reference/revisions/ba91ff4c6969/schema)
