---
title: "Create a single purchase order"
method: POST
path: "/purchase-orders"
tags: ["purchaseOrders"]
---

# Create a single purchase order

`POST /purchase-orders`

Creates a new purchase order with the provided details. The `po_number` field is required and must be provided by the client (no auto-generation).

## Headers

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

## Request body

- PurchaseOrderCreateRequest
  - `ottimate_location_id` integer, required
  - `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` PurchaseOrderCreateRequestItemsItems[], required
    - `external_id` string
    - `name` string, required
    - `sku` string
    - `quantity` number, double, required
    - `price` number, double, required
    - `uom` string
    - `dimensions` PurchaseOrderCreateRequestItemsItemsDimensions — 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` PurchaseOrderCreateRequestCustomFields — 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 `201`

Successfully created

- PurchaseOrderCreateResponse
  - `id` string, required
  - `external_id` string
  - `po_number` string
  - `status` 'pending' | 'open' | 'received' | 'closed' | 'flagged' | 'archived' | 'deleted', required
  - `ottimate_location_id` integer
  - `ottimate_company_id` integer
  - `date` string, date
  - `erp_vendor_id` string
  - `erp_vendor_name` string
  - `total_amount` number, double
  - `items_count` integer
  - `items` PurchaseOrderCreateResponseItemsItems[]
    - `id` string
    - `external_id` string
    - `name` string, required
    - `sku` string
    - `quantity` number, double, required
    - `price` number, double, required
    - `uom` string
    - `dimensions` PurchaseOrderCreateResponseItemsItemsDimensions — Resolved dimensions keyed by dimension type. Each value is an object containing the dimension's id, erp_dimension_id, name, and code — unlike the POST/PATCH request format which expects plain string values.
    - `created_date` string, date-time
    - `last_modified_date` string, date-time
  - `created_date` string, date-time — Creation timestamp. UTC ISO 8601, e.g. "2024-01-15T10:30:00Z".
  - `custom_fields` PurchaseOrderCreateResponseCustomFields — Optional custom fields configured for this company's purchase orders

## Other responses

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

## Changes

- **2026-08-27** `ba91ff4c6969` — 2 breaking
  - the `id` response's property type/format changed from `string`/`uuid` to `string`/`` for status `201`
  - the `items/items/id` response's property type/format changed from `string`/`uuid` to `string`/`` for status `201`
- **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/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)
