Purchase orders
A purchase order records products or services ordered from a supplier, along with receiving dates, purchasing costs, taxes, shipping, and payments. API v3 can create, update, send, receive, delete, and create or delete manual payments against eligible purchase orders.
The purchase order object
| Field | Type | Description |
|---|---|---|
id | string | Unique purchase-order UUID. |
object | string | Always purchase_order. |
purchase_order_number | integer | Account-assigned purchase-order number. |
custom_purchase_order_number | string or null | Optional custom purchase-order number. |
name | string or null | Purchase-order name. |
supplier_id | string | Supplier UUID. |
supplier_name | string | Supplier display name stored with the purchase order. |
assigned_user_id | string | SalesBinder user UUID assigned to the purchase order. |
location_id | string or null | Inventory location associated with the purchase order. |
status_id | integer | Current purchase-order status identifier. |
status | string or null | Current status name, such as Not Sent, Sent, Partially Received, or Received. |
issue_date | string or null | Issue date in YYYY-MM-DD format. |
date_sent | string or null | Date sent in YYYY-MM-DD format. |
date_received | string or null | Received date in YYYY-MM-DD format. |
date_requested | string or null | Requested date in YYYY-MM-DD format. |
date_needed | string or null | Needed-by date in YYYY-MM-DD format. |
date_fully_paid | string or null | Fully paid date in YYYY-MM-DD format. |
requested_from | string or null | Person or team that requested the purchase order. |
attention | string or null | Attention line. |
shipping_address | string or null | Shipping-address text. |
public_note | string or null | Supplier-facing note. |
payment_terms | string or null | Payment terms. |
shipping_provider | string or null | Shipping provider. |
shipping_tracking_code | string or null | Shipping tracking code. |
subtotal | string | Subtotal before shipping and taxes, as a four-decimal string. |
shipping | string | Shipping charge as a four-decimal string. |
tax | string | Primary tax amount as a four-decimal string. |
tax_2 | string | Secondary tax amount as a four-decimal string. |
total | string | Purchase-order total including shipping and taxes, as a four-decimal string. |
amount_paid | string | Applied purchase-order payments as a four-decimal string. |
amount_due | string | Remaining amount due as a four-decimal string. |
created_at | string or null | ISO 8601 creation timestamp. |
updated_at | string or null | ISO 8601 modification timestamp. |
lines | array | Current purchase-order lines. Present only when retrieving one purchase order. |
Monetary values use the SalesBinder account's base currency.
The purchase order line object
| Field | Type | Description |
|---|---|---|
id | string | Unique purchase-order-line UUID. |
object | string | Always purchase_order_line. |
item_id | string or null | Related inventory item UUID. |
item_variation_location_id | integer or null | Related item variation and location identifier. |
name | string or null | Line-item name. |
description | string or null | Line-item description. |
quantity | number | Quantity ordered. |
quantity_received | number | Quantity already received. |
unit_id | integer or null | Related unit identifier. |
unit_cost | string | Purchasing cost per unit as a four-decimal string. |
discount_percent | string | Discount percentage as a three-decimal string. |
discounted_unit_cost | string or null | Discounted unit cost, or null when no discounted cost is stored. |
tax_rate | string | Primary tax percentage as a three-decimal string. |
tax_2_rate | string | Secondary tax percentage as a three-decimal string. |
subtotal | string | Quantity multiplied by the effective unit cost, before tax, as a four-decimal string. |
The unit_cost field is the purchasing amount recorded on the purchase order.
The purchase-order payment object
| Field | Type | Description |
|---|---|---|
id | string | Unique payment UUID. |
object | string | Always payment. |
purchase_order_id | string | Purchase-order UUID to which the payment or refund applies. |
amount | string | Signed amount as a four-decimal string. Payments are positive and refunds are negative. |
type | string | payment for a positive amount or refund for a negative amount. |
reference | string | Stored payment or refund reference. |
payment_date | string or null | Payment date in YYYY-MM-DD format. |
card | null | Always null; card details are not available for purchase-order payments. |
Create a purchase order
POST/api/v3/purchase-orders
Required scope: purchase_orders:write
Creates a purchase order in the Not Sent status. SalesBinder assigns the purchase-order number and current API user, calculates totals, and returns the complete purchase order with its lines.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
supplier_id | string | Yes | UUID of an active supplier in the current account. |
location_id | string | Yes | UUID of the active inventory location that will receive the order. |
lines | array | Yes | Between 1 and 100 inventory or service lines. |
name | string | No | Optional name for your own reference. |
issue_date | string | No | Issue date in YYYY-MM-DD format. Defaults to the current date in the user's account timezone. |
date_requested | string | No | Requested date in YYYY-MM-DD format. |
date_needed | string | No | Needed-by date in YYYY-MM-DD format. |
requested_from | string | No | Person or team requesting the purchase order. |
custom_purchase_order_number | string | No | Custom identifier of up to 24 characters. |
attention | string | No | Attention line. |
shipping_address | string | No | Shipping-address text. |
public_note | string | No | Supplier-facing note. |
payment_terms | string | No | Payment terms. |
shipping | number | No | Non-negative shipping charge. Defaults to 0. |
shipping_provider | string | No | Shipping provider. |
shipping_tracking_code | string | No | Shipping tracking code. |
discount_percent | number | No | Purchase-order-wide discount from 0 through 100. |
Line fields
| Field | Type | Required | Description |
|---|---|---|---|
item_id | string | Inventory lines | UUID of an active inventory item in the purchase-order location. Omit for a service line. |
item_variation_location_id | integer | Variation items | Identifier of the variation at the purchase-order location. |
name | string | Service lines | Service-line name. Inventory line names come from the selected item. |
description | string | No | Line description. Inventory lines default to the item's description. |
quantity | number | No | Positive quantity. Defaults to 1; unique inventory items are always ordered as one. |
unit_cost | number | Service lines | Non-negative purchasing cost. Inventory lines default to the item's resolved unit cost and may be overridden. |
tax_rate | number | No | Primary tax percentage from 0 through 100. Defaults to the supplier's primary tax rate. |
tax_2_rate | number | No | Secondary tax percentage from 0 through 100. Defaults to the supplier's secondary tax rate. |
Example request
curl "https://yourbusiness.salesbinder.com/api/v3/purchase-orders" \
--request POST \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: warehouse-order-4021" \
--data '{
"supplier_id": "709d2a43-12a9-4d85-a9d9-cb16e66cef53",
"location_id": "6d503033-433d-40f2-83a8-692687bfb384",
"issue_date": "2026-07-19",
"date_needed": "2026-07-31",
"shipping": 12.5,
"lines": [
{
"item_id": "d2fb4300-50ad-468f-a603-d5978acabb2e",
"quantity": 5
},
{
"name": "Setup service",
"quantity": 1,
"unit_cost": 50
}
]
}'The optional Idempotency-Key supports short-lived replay. Repeating the same request with the same key during that window returns the original 201 response and includes Idempotent-Replayed: true. Reusing the key with different request data returns a conflict.
The API does not accept account, assigned-user, status, purchase-order-number, payment, receiving, total, cost-snapshot, or timestamp fields. Those values are controlled by SalesBinder.
Update a purchase order
PATCH/api/v3/purchase-orders/{purchase_order_id}
Required scope: purchase_orders:write
Updates supported fields on a purchase order in the Not Sent status. Sent, partially received, and received purchase orders cannot be updated through this endpoint.
PATCH requests are partial. Fields omitted from the request retain their current values. The supported detail fields are the same fields accepted when creating a purchase order.
Line replacement
If lines is omitted, every existing active line is preserved. If lines is supplied, it is the complete desired list of active lines:
- Include an existing line's
idto update and preserve that line. - Omit an existing line to remove it from the active purchase order.
- Omit
idto add a new line. - Each supplied line must contain the complete inventory-line or service-line data required for creation.
- Discount lines are controlled with the top-level
discount_percentfield and must not be submitted directly. - A line ID must belong to the purchase order being updated and can appear only once.
Changing supplier_id or location_id requires lines in the same request. This ensures that supplier tax defaults and every inventory item's receiving location are revalidated together.
Example request
curl "https://yourbusiness.salesbinder.com/api/v3/purchase-orders/c40e5d25-c573-48ec-aa46-9737eddf2513" \
--request PATCH \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: revise-warehouse-order-4021" \
--data '{
"date_needed": "2026-08-05",
"shipping": 15,
"lines": [
{
"id": "6087fabb-5252-42ef-948b-584ec3eb89f5",
"item_id": "d2fb4300-50ad-468f-a603-d5978acabb2e",
"quantity": 8,
"unit_cost": 19.5
},
{
"name": "Expedited handling",
"quantity": 1,
"unit_cost": 35
}
]
}'The optional Idempotency-Key follows the same short-lived replay behavior as purchase-order creation.
The update does not change the purchase-order number or allocate another sequence number. It also does not change status, received quantities, payments, on-hand inventory, or incoming inventory.
Mark a purchase order as sent
POST/api/v3/purchase-orders/{purchase_order_id}/send
Required scope: purchase_orders:send
Marks an eligible Not Sent purchase order as Sent. This is a separate workflow permission from purchase_orders:write, so a restricted key must include the send scope explicitly.
The request body is optional. Supply date_sent in YYYY-MM-DD format to choose the sent date. If omitted, SalesBinder uses the current date in the API user's account timezone.
Example request
curl "https://yourbusiness.salesbinder.com/api/v3/purchase-orders/c40e5d25-c573-48ec-aa46-9737eddf2513/send" \
--request POST \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: send-warehouse-order-4021" \
--data '{
"date_sent": "2026-07-20"
}'The response is the complete purchase order with its status, sent date, and lines. The purchase-order number, totals, payments, received quantities, and line IDs are preserved.
Calling the endpoint again for a purchase order that is already Sent is safe. SalesBinder preserves the original date_sent and schedules the same incoming-inventory refresh again. Partially received and received purchase orders cannot use this endpoint.
The optional Idempotency-Key follows the same short-lived replay behavior as purchase-order creation and update. A replay returns the original response with Idempotent-Replayed: true.
Receive purchase-order quantities
POST/api/v3/purchase-orders/{purchase_order_id}/receive
Required scope: purchase_orders:receive
Records incremental quantities received against inventory lines on a Sent or Partially Received purchase order. Each request supplies the additional quantity received now, rather than the desired lifetime total.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
lines | array | Yes | Between 1 and 100 inventory lines to receive. |
received_date | string | No | Final received date in YYYY-MM-DD format. Stored only when this request fully receives the purchase order. Defaults to the current date in the API user's account timezone. |
Line fields
| Field | Type | Required | Description |
|---|---|---|---|
line_id | string | Yes | UUID of an inventory line on this purchase order. Service lines cannot be received through this endpoint. |
quantity | number | Yes | Positive incremental quantity that does not exceed the line's remaining unreceived quantity. |
Example request
curl "https://yourbusiness.salesbinder.com/api/v3/purchase-orders/c40e5d25-c573-48ec-aa46-9737eddf2513/receive" \
--request POST \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: warehouse-receipt-4021-1" \
--data '{
"received_date": "2026-07-21",
"lines": [
{
"line_id": "6087fabb-5252-42ef-948b-584ec3eb89f5",
"quantity": 3
}
]
}'The response is the complete updated purchase order. A partial receipt changes the status to Partially Received and leaves date_received unset. Once every inventory line is fully received, the status changes to Received and SalesBinder stores the supplied or default received date.
The optional Idempotency-Key follows the same short-lived replay behavior as other purchase-order writes. It is strongly recommended for warehouse integrations so an immediate retry cannot apply the same incremental quantities twice.
Drop-shipped purchase orders, inactive receiving locations, draft or already received purchase orders, service lines, duplicate line IDs, and quantities above the remaining balance are rejected. The receipt and all line quantities are saved together or not at all.
List purchase orders
GET/api/v3/purchase-orders
Required scope: purchase_orders:read
Returns visible active purchase orders ordered by purchase-order number, newest first. Line items are omitted from list responses.
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number. Defaults to 1. |
limit | integer | No | Records per page. Defaults to 20; maximum 100. |
q | string | No | Searches supplier name, custom purchase-order number, and purchase-order name. A numeric value also matches an exact purchase-order number. |
supplier_id | string | No | Returns purchase orders for the supplier UUID. |
status_id | integer | No | Returns purchase orders with the status identifier. |
location_id | string | No | Returns purchase orders associated with the inventory location UUID. |
issue_date_from | string | No | Includes purchase orders issued on or after this YYYY-MM-DD date. |
issue_date_to | string | No | Includes purchase orders issued on or before this YYYY-MM-DD date. |
requested_date_from | string | No | Includes purchase orders requested on or after this date. |
requested_date_to | string | No | Includes purchase orders requested on or before this date. |
needed_date_from | string | No | Includes purchase orders needed on or after this date. |
needed_date_to | string | No | Includes purchase orders needed on or before this date. |
received_date_from | string | No | Includes purchase orders received on or after this date. |
received_date_to | string | No | Includes purchase orders received on or before this date. |
All date filters require YYYY-MM-DD format.
Example request
curl "https://yourbusiness.salesbinder.com/api/v3/purchase-orders?supplier_id=709d2a43-12a9-4d85-a9d9-cb16e66cef53&limit=20" \
--header "Authorization: Bearer YOUR_API_KEY"Example response
{
"object": "list",
"url": "/api/v3/purchase-orders",
"has_more": false,
"data": [
{
"id": "c40e5d25-c573-48ec-aa46-9737eddf2513",
"object": "purchase_order",
"purchase_order_number": 4021,
"supplier_id": "709d2a43-12a9-4d85-a9d9-cb16e66cef53",
"supplier_name": "Example Supplier",
"status_id": 18,
"status": "Sent",
"issue_date": "2026-07-18",
"subtotal": "100.0000",
"shipping": "10.0000",
"tax": "5.5000",
"tax_2": "2.2000",
"total": "117.7000",
"amount_paid": "25.0000",
"amount_due": "92.7000"
}
],
"pagination": {
"page": 1,
"per_page": 20,
"total_pages": 1,
"total_records": 1
}
}Examples may omit unchanged fields for readability.
Retrieve a purchase order
GET/api/v3/purchase-orders/{purchase_order_id}
Required scope: purchase_orders:read
Returns one visible active purchase order. The response includes the lines array in stored line order. Deleted lines are excluded.
Example request
curl "https://yourbusiness.salesbinder.com/api/v3/purchase-orders/c40e5d25-c573-48ec-aa46-9737eddf2513" \
--header "Authorization: Bearer YOUR_API_KEY"If the purchase order is outside the current account or assigned-user boundary, is a different document type, has been archived, or does not exist, the API returns 404 resource_missing.
List purchase-order payments
GET/api/v3/purchase-orders/{purchase_order_id}/payments
Required scope: purchase_orders:read
Returns recorded payments and refunds for one visible purchase order, ordered by payment date with the newest first. Purchase-order payments are separate from invoice payments.
| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number. Defaults to 1. |
limit | integer | No | Records per page from 1 through 100. Defaults to 20. |
curl "https://yourbusiness.salesbinder.com/api/v3/purchase-orders/c40e5d25-c573-48ec-aa46-9737eddf2513/payments?limit=20" \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Accept: application/json"{
"object": "list",
"url": "/api/v3/purchase-orders/c40e5d25-c573-48ec-aa46-9737eddf2513/payments",
"has_more": false,
"data": [
{
"id": "2ce987a5-19a8-4bbe-ae2b-cff6da9fbfab",
"object": "payment",
"purchase_order_id": "c40e5d25-c573-48ec-aa46-9737eddf2513",
"amount": "50.0000",
"type": "payment",
"reference": "Check 123",
"payment_date": "2026-07-21",
"card": null
}
],
"pagination": {
"page": 1,
"per_page": 20,
"total_pages": 1,
"total_records": 1
}
}The endpoint applies the same account, purchase-order type, active-record, assigned-user visibility, and permission boundaries as purchase-order retrieval. It never returns payments from another purchase order or account. An eligible purchase order with no recorded payments returns an empty data array and zero pagination totals.
Record a purchase-order payment
POST/api/v3/purchase-orders/{purchase_order_id}/payments
Required scope: purchase_orders:payments
Records a positive manual payment against the current purchase-order balance and returns the purchase-order payment object with 201 Created. The account must have purchase-order payments enabled, and the purchase order must be Sent, Partially Received, or Received.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
amount | number or numeric string | Yes | Positive payment amount with no more than two decimal places. It cannot exceed the remaining balance. |
payment_date | string | Yes | Payment date in YYYY-MM-DD format. |
reference | string | No | Optional payment reference up to 255 characters. |
curl "https://yourbusiness.salesbinder.com/api/v3/purchase-orders/c40e5d25-c573-48ec-aa46-9737eddf2513/payments" \
--request POST \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: po-payment-20260720-001" \
--data '{
"amount": "125.50",
"payment_date": "2026-07-20",
"reference": "Bank transfer 1042"
}'{
"id": "2ce987a5-19a8-4bbe-ae2b-cff6da9fbfab",
"object": "payment",
"purchase_order_id": "c40e5d25-c573-48ec-aa46-9737eddf2513",
"amount": "125.5000",
"type": "payment",
"reference": "Bank transfer 1042",
"payment_date": "2026-07-20",
"card": null
}The payment and the purchase order's amount_paid, amount_due, and date_fully_paid values are updated together. SalesBinder rechecks the current balance and prevents concurrent or stale requests from overpaying the purchase order. A fully paid or ineligible purchase order returns 409 purchase_order_payment_not_allowed. Invalid amounts, dates, and fields return a field-specific 422 error.
Use an optional Idempotency-Key when retrying the same logical payment. An identical retry within the short idempotency window returns the original 201 response with Idempotent-Replayed: true; reusing the key with different request data returns 409 idempotency_key_reused.
Delete a purchase-order payment
DELETE/api/v3/purchase-orders/{purchase_order_id}/payments/{payment_id}
Required scope: purchase_orders:payments
Deletes one positive manual payment and recalculates the purchase order's paid state as part of the same operation. Use this endpoint when a payment was entered in error or the purchase order should no longer be marked as paid.
curl "https://yourbusiness.salesbinder.com/api/v3/purchase-orders/c40e5d25-c573-48ec-aa46-9737eddf2513/payments/2ce987a5-19a8-4bbe-ae2b-cff6da9fbfab" \
--request DELETE \
--header "Authorization: Bearer YOUR_API_KEY"{
"id": "2ce987a5-19a8-4bbe-ae2b-cff6da9fbfab",
"object": "payment",
"purchase_order_id": "c40e5d25-c573-48ec-aa46-9737eddf2513",
"deleted": true
}The payment must belong to the visible purchase order and current account. Negative historical adjustment records cannot be deleted through this endpoint, and SalesBinder returns 409 purchase_order_payment_delete_not_allowed if deleting a payment would leave a negative paid balance. Deleting a payment from a fully paid purchase order clears date_fully_paid when a balance becomes due again.
Payment deletion does not use an idempotency key. Repeating a completed deletion returns 404 resource_missing because the payment no longer exists.
Delete a purchase order
DELETE/api/v3/purchase-orders/{purchase_order_id}
Required scope: purchase_orders:delete
Deletes an eligible purchase order and its lines. Deletion is limited to a Not Sent purchase order for which no related processing has begun. The purchase order must have:
- no payments;
- no received quantities or received date;
- no sent date;
- no drop-shipping activity;
- no associated sales order or other linked document; and
- no packing list or shipping shipment.
SalesBinder returns 409 purchase_order_delete_not_allowed when the purchase order exists within the key's visibility boundary but does not meet every deletion condition. Deleting a purchase order never deletes related payments, sales orders, packing lists, or shipments.
Example request
curl "https://yourbusiness.salesbinder.com/api/v3/purchase-orders/c40e5d25-c573-48ec-aa46-9737eddf2513" \
--request DELETE \
--header "Authorization: Bearer YOUR_API_KEY"Example response
{
"id": "c40e5d25-c573-48ec-aa46-9737eddf2513",
"object": "purchase_order",
"deleted": true
}Deleting a not-sent draft does not change on-hand or incoming inventory quantities. The purchase order and its lines are deleted together, and related account totals and activity are refreshed automatically.
Permissions and write behavior
API key scopes can reduce access but cannot exceed the current user's SalesBinder permissions. Purchase-order access requires the current purchase-order and unit-cost permissions. Without current view-all-purchase-orders permission, operations are limited to purchase orders assigned to the user. Creation, receiving, and managing payments also require current purchase-order-modify permission and follow the user's inventory-location restriction.
If a dedicated purchase-order permission is not configured, SalesBinder may use the corresponding inventory-modify permission. An explicit purchase-order permission denial is always respected.
Receiving is limited to incremental inventory-line quantities on sent, non-drop-shipped purchase orders. To correct a positive manual payment entered in error, delete that payment; API v3 does not create a separate purchase-order refund record. API v3 does not support service-only receiving, archiving, or restoring purchase orders. Unsupported fields and actions are rejected.