Browse the documentation

MCP tools

Sales and purchase orders

MCP tools for sales orders from customers and purchase orders to suppliers, including goods receipts.

A sales order is what a customer ordered from your organization, and a purchase order is what your organization ordered from a supplier. Deliveries fulfil a sales order, while what arrives from a supplier is recorded with the receipt tool on this page. The orders guide explains the three steps in the app; these tools do the same things from Claude or from an MCP client you build.

Note:Every tool on this page belongs to the Pro and Enterprise plans. Sales orders are open to every role except technical and purchasing, and the viewer (no pricing) role sees them without prices. Purchase orders are cost data, so only the owner, admin, purchasing and viewer roles see them.
Tip:Order lines are edited by ID. Fetch the order first, then send the complete line list back: a line with its id is changed in place, a line without one is added, and a line you leave out is deleted. Changing a line in place is what keeps a sales order line linked to its deliveries and a purchase order line's received quantity.
ToolWhat it does
sales_orders_listList sales orders
sales_orders_getGet a sales order
sales_orders_createCreate a sales order
sales_orders_updateUpdate a sales order
sales_orders_set_statusSet a sales order's status
sales_orders_deleteDelete a sales order
sales_orders_create_deliveriesPlan a sales order's deliveries
sales_orders_mark_deliveredMark a sales order delivered in full
sales_orders_calendarDelivery calendar
purchase_orders_listList purchase orders
purchase_orders_getGet a purchase order
purchase_orders_createCreate a purchase order
purchase_orders_updateUpdate a purchase order
purchase_orders_set_statusSet a purchase order's status
purchase_orders_deleteDelete a purchase order
purchase_orders_receiveRecord a goods receipt

Sales orders

A sales order's status runs new, confirmed, in_progress and fulfilled, or ends in cancelled. Every order gets a sequential number for your organization: SO-000001, then SO-000002 and so on.

sales_orders_list

Lists your organization's sales orders, newest first, each with its tender and quotation. Filter by status, tender or quotation, or search the order number, the customer's name or the customer's own reference.

Read-only · scope orders.read · roles: owner, admin, sales, viewer, viewer (no pricing) · Pro and Enterprise plans

ParameterTypeRequiredDescription
statusstringNoOnly orders in this status: new, confirmed, in_progress, fulfilled or cancelled.
hide_fulfilledbooleanNoSend true to leave fulfilled orders out, as the sales orders page does by default. It has no effect when you send status.
tender_idintegerNoOnly orders won on this tender.
quotation_idintegerNoOnly orders that accepted this quotation.
qstringNoText to look for in the order number, the customer's name and the customer's reference; it matches part of the text. Up to 200 characters.
pageintegerNoPage number, starting at 1.
page_sizeintegerNoResults per page: 20 by default, 100 at most.

Returns: A page of orders with total and total_pages. Each order carries its number, customer, status, dates, currency, total_amount, tender and quotation.

  • The viewer (no pricing) role sees the orders without total_amount.
  • A status that is not one of the listed values is refused with a 400.

sales_orders_get

Returns one sales order with everything around it: its lines and how much of each has been delivered, the overall fulfilment, where the deliveries differ from the order, the tender and quotation, the linked deliveries, and the purchase orders sourcing its goods.

Read-only · scope orders.read · roles: owner, admin, sales, viewer, viewer (no pricing) · Pro and Enterprise plans

ParameterTypeRequiredDescription
idintegerYesThe sales order's ID, from sales_orders_list.

Returns: The order in sales_order, its lines in items, then fulfilment, deviations, tender, quotation, deliveries, purchase_orders and documents.

  • Each line has delivered_quantity (on deliveries marked delivered), pending_quantity (on deliveries still draft, scheduled or on the way), remaining_quantity and excess_quantity (delivered beyond what was ordered). A cancelled delivery counts for nothing.
  • deviations names every way the deliveries differ from the order: over_delivered (a line delivered beyond its ordered quantity), extra_lines (lines delivered outside the order), substitutions (a different catalog product shipped), late_deliveries (a delivery delivered or scheduled after due_on) and closed_short (the order marked fulfilled while quantities remain), with a count of them all. They are a warning and block nothing.
  • The viewer (no pricing) role gets the order without total_amount and without unit_price on the lines. purchase_orders comes back null for the sales and viewer (no pricing) roles, because purchase orders name suppliers and their costs.
  • documents are the files kept on the order, first of all the customer's purchase order as a PDF. Each has a path, a name, a size and a url valid for about an hour. The path is what `sales_order_document_delete` takes. Every role that sees sales orders sees them.
  • An order that is not in your organization answers 404.

sales_orders_create

Records an order that came in from a customer, with its lines. It assigns the next sequential number, starts the order as new, and computes the total from the priced lines only.

Changes data · scope orders.write · roles: owner, admin, sales · Pro and Enterprise plans

ParameterTypeRequiredDescription
customer_idintegerNoThe customer profile, from `customers_list`. When you leave customer_name out, the order takes the customer's legal name, or else the display name. Send null for no link.
customer_namestringNoWho ordered, 1 to 200 characters. Required unless you send customer_id.
customer_referencestringNoThe customer's own reference, such as their purchase order or contract number, up to 200 characters. Send null to clear it.
tender_idintegerNoThe tender the order was won on, from the tender tools. Send null to leave it empty.
quotation_idintegerNoThe quotation the customer accepted, from `quotations_list`. It must be your organization's quotation. Send null to leave it empty.
currencystringNoThe three-letter currency code (ISO 4217), such as SAR. Defaults to SAR, and is stored in capitals.
ordered_onstringNoThe order date, as YYYY-MM-DD. Defaults to today in Riyadh.
due_onstringNoThe date the customer expects delivery by, as YYYY-MM-DD. Send null to clear it.
notesstringNoNotes on the order, up to 2,000 characters. Send null to clear them.
itemsobject[]YesThe order lines, from 1 to 500.
items[].idintegerNoNot used when creating; leave it out.
items[].product_idintegerNoThe catalog product this line is for, from products_list. It must be your organization's product. Send null to remove the link.
items[].descriptionstringYesWhat was ordered, 1 to 1,000 characters.
items[].quantitynumberYesThe quantity ordered; it must be above zero.
items[].unitstringNoThe unit of measure, such as box, up to 50 characters. Send null to clear it.
items[].unit_pricenumberNoThe price per unit in the order's currency, zero or more. Leave it out or send null while the line has no price; it then stays out of the order total.
items[].notesstringNoNotes on the line, up to 1,000 characters. Send null to clear them.
items[].tender_item_idintegerNoThe tender item this line answers, from tenders_get. Useful when the order comes from a quotation or a tender. Send null to remove the link.
items[].line_numberstringNoThe line number as the customer prints it on their purchase order, such as 10 or 20, up to 50 characters. Left out on an update it stays as it is; send null to clear it.
items[].material_codestringNoThe customer's item code, such as the trade number on a NUPCO purchase order, up to 50 characters. Left out on an update it stays as it is; send null to clear it.
items[].ship_tostringNoWhere this line is delivered, as the purchase order prints it, such as a NUPCO warehouse or a health directorate, up to 300 characters. One order can send its lines to many destinations, and `sales_orders_create_deliveries` turns them into one draft delivery per destination. Left out on an update it stays as it is; send null to clear it.
items[].due_onstringNoThe delivery deadline of this line as YYYY-MM-DD, the date the purchase order gives for it. sales_orders_calendar places the line on the delivery calendar by it. Left out on an update it stays as it is; send null to clear it.
{
  "customer_name": "Al Noor Hospital",
  "customer_reference": "PO-2026-0457",
  "tender_id": 48213,
  "quotation_id": 1207,
  "ordered_on": "2026-10-04",
  "due_on": "2026-11-15",
  "items": [
    {
      "description": "Sterile syringe 5 ml, box of 100",
      "quantity": 200,
      "unit": "box",
      "unit_price": 36.5,
      "tender_item_id": 902114
    },
    {
      "description": "Nitrile gloves, medium, box of 100",
      "quantity": 500,
      "unit": "box",
      "unit_price": 21
    }
  ]
}
Example arguments

Returns: The new order's sales_order_id and order_number.

  • A name is required: send customer_name, or customer_id and the order takes the customer's name from the profile. A name you send wins over the profile's. With neither, the tool answers 400.
  • total_amount counts only the lines that have a unit_price. When no line is priced, the order has no total.
  • A tender you cannot see, or a quotation, customer or product that is not your organization's, answers 404.
  • To fulfil the order, create deliveries linked to it with `deliveries_create`. The order moves to in_progress once the first delivery exists, and to fulfilled when every line is delivered.

sales_orders_update

Changes an order's customer, dates, links, notes or lines. Only what you send changes, and null clears an optional field. The number and the status cannot be edited here: use `sales_orders_set_status` for the status.

Changes data · scope orders.write · roles: owner, admin, sales · Pro and Enterprise plans

ParameterTypeRequiredDescription
idintegerYesThe sales order's ID.
customer_idintegerNoThe customer profile linked to the order, from `customers_list`. Send null to unlink. Linking does not change the customer name written on the order, so send customer_name too if you want that.
customer_namestringNoWho ordered, 1 to 200 characters.
customer_referencestringNoThe customer's own reference, such as their purchase order or contract number, up to 200 characters. Send null to clear it.
tender_idintegerNoThe tender the order was won on, from the tender tools. Send null to leave it empty.
quotation_idintegerNoThe quotation the customer accepted, from `quotations_list`. It must be your organization's quotation. Send null to leave it empty.
currencystringNoThe three-letter currency code (ISO 4217), such as SAR. Defaults to SAR, and is stored in capitals.
ordered_onstringNoThe order date, as YYYY-MM-DD.
due_onstringNoThe date the customer expects delivery by, as YYYY-MM-DD. Send null to clear it.
notesstringNoNotes on the order, up to 2,000 characters. Send null to clear them.
itemsobject[]NoThe complete line list, reconciled by ID (see the top of this page), from 1 to 500 lines. Leave it out to keep the lines and the total as they are.
items[].idintegerNoThe stored line's ID, from sales_orders_get. A line sent with its ID is changed in place; a line without one is added.
items[].product_idintegerNoThe catalog product this line is for, from products_list. It must be your organization's product. Send null to remove the link.
items[].descriptionstringYesWhat was ordered, 1 to 1,000 characters.
items[].quantitynumberYesThe quantity ordered; it must be above zero.
items[].unitstringNoThe unit of measure, such as box, up to 50 characters. Send null to clear it.
items[].unit_pricenumberNoThe price per unit in the order's currency, zero or more. Leave it out or send null while the line has no price; it then stays out of the order total.
items[].notesstringNoNotes on the line, up to 1,000 characters. Send null to clear them.
items[].tender_item_idintegerNoThe tender item this line answers, from tenders_get. Useful when the order comes from a quotation or a tender. Send null to remove the link.
items[].line_numberstringNoThe line number as the customer prints it on their purchase order, such as 10 or 20, up to 50 characters. Left out on an update it stays as it is; send null to clear it.
items[].material_codestringNoThe customer's item code, such as the trade number on a NUPCO purchase order, up to 50 characters. Left out on an update it stays as it is; send null to clear it.
items[].ship_tostringNoWhere this line is delivered, as the purchase order prints it, such as a NUPCO warehouse or a health directorate, up to 300 characters. One order can send its lines to many destinations, and `sales_orders_create_deliveries` turns them into one draft delivery per destination. Left out on an update it stays as it is; send null to clear it.
items[].due_onstringNoThe delivery deadline of this line as YYYY-MM-DD, the date the purchase order gives for it. sales_orders_calendar places the line on the delivery calendar by it. Left out on an update it stays as it is; send null to clear it.
{
  "id": 214,
  "due_on": "2026-11-30",
  "items": [
    {
      "id": 1881,
      "description": "Sterile syringe 5 ml, box of 100",
      "quantity": 250,
      "unit": "box",
      "unit_price": 36.5
    },
    {
      "description": "Examination gloves, large, box of 100",
      "quantity": 100,
      "unit": "box",
      "unit_price": 21
    }
  ]
}
Example arguments

Returns: The sales_order_id of the updated order.

  • A line ID that is not on this order, or that is sent twice, is refused with 400. A line you leave out of the list is deleted, and any delivery line that pointed at it loses that link.
  • When you send items, the total is recomputed from the new lines.
  • The tender, quotation and customer are checked as they are when creating, and one that cannot be found answers 404.

sales_orders_set_status

Moves a sales order to a new status. Any status may follow any other, so a mistaken move can be undone. This is the manual override of what deliveries move on their own.

Changes data · scope orders.write · roles: owner, admin, sales · Pro and Enterprise plans

ParameterTypeRequiredDescription
idintegerYesThe sales order's ID.
statusstringYesThe new status: new, confirmed, in_progress, fulfilled or cancelled.
{
  "id": 214,
  "status": "confirmed"
}
Example arguments

Returns: A confirmation with the new status.

  • Entering fulfilled stamps fulfilled_at, and leaving it clears the stamp.
  • Linked deliveries also move the order on their own, but only forward: to in_progress once the first delivery exists and to fulfilled when every line is delivered. They never move it back, and never out of cancelled or fulfilled.

sales_orders_delete

Deletes a sales order and its lines. The deliveries and purchase orders that pointed at it stay and are unlinked from it. This cannot be undone.

Deletes or overwrites data · scope orders.write · roles: owner, admin, sales · Pro and Enterprise plans

ParameterTypeRequiredDescription
idintegerYesThe sales order's ID.

Returns: A confirmation of the deletion.

sales_orders_create_deliveries

Creates one draft delivery for each destination and day the order's lines name in ship_to and due_on, each carrying the lines that go there. A NUPCO purchase order that sends one product to twelve warehouses becomes twelve drafts in one call.

Changes data · scope orders.write or logistics.write · roles: owner, admin · Pro and Enterprise plans

ParameterTypeRequiredDescription
idintegerYesThe sales order's ID, from sales_orders_list.
warehouse_idintegerNoThe warehouse every delivery ships from, from warehouses_list. Leave it out to choose later, or send null for none.
destinationsobject[]NoExtra details for the destinations the lines name: an address, a city or a person to call on delivery. They are matched by the ship_to text, ignoring case and extra spaces. Up to 200.
destinations[].ship_tostringYesThe destination exactly as the lines spell it in ship_to, 1 to 300 characters.
destinations[].addressstringNoThe destination's street address, up to 500 characters.
destinations[].citystringNoThe city, up to 100 characters.
destinations[].contact_namestringNoThe person to call on delivery, up to 200 characters.
destinations[].contact_phonestringNoTheir phone number, up to 50 characters.
{
  "id": 1042,
  "warehouse_id": 3,
  "destinations": [
    {
      "ship_to": "NUPCO C.WH in Jeddah for MOH - MOH - Taif",
      "contact_name": "Receiving desk",
      "contact_phone": "+966500000000"
    }
  ]
}
Example arguments

Returns: deliveries: for each draft its delivery_id, delivery_number, destination_name, due_on and the IDs of the order lines on it. Then skipped: the lines that were not planned and why, no_ship_to or fully_planned.

  • It plans only what no live delivery carries yet, so calling it again creates nothing new, and a line that has shipped in part gets a draft for the rest. A line with no ship_to is skipped and listed in skipped.
  • Each draft is scheduled for noon Riyadh time on its lines' due day, and a line with no date of its own goes on the order's due date, as on the calendar. The order's status does not move until one of the deliveries is worked on.
  • It needs the admin or owner role because it creates deliveries, and both the orders.write and logistics.write scopes. A cancelled order answers 409, and so does an order whose deliveries are being planned at that moment from somewhere else: wait a minute, then call again to plan whatever is left.
  • If a draft cannot be created the call stops and says how many were created before it. Those stay, and calling again plans only what is left.

sales_orders_mark_delivered

Records a sales order as delivered in full, such as an order invoiced in Zoho Books: every open delivery of the order becomes delivered, whatever is left gets a delivery per destination that is delivered at once, and the order then closes as fulfilled.

Changes data · scope orders.write or logistics.write · roles: owner, admin · Pro and Enterprise plans

ParameterTypeRequiredDescription
idintegerYesThe sales order's ID, from sales_orders_list.
notestringNoA note written on the deliveries it creates, up to 500 characters. By default it says the order was invoiced in Zoho Books.
{
  "id": 1042
}
Example arguments

Returns: delivered: the IDs of the deliveries it set delivered. created: the IDs of the deliveries it made.

  • Cancelled deliveries are left as they are and an order already delivered in full does not change, so calling it again is safe. A cancelled order answers 409. To record part of an order, use deliveries_create and deliveries_set_status for those lines.
  • It needs the admin or owner role because it creates deliveries and moves their status, and both the orders.write and logistics.write scopes.

sales_orders_calendar

Shows the days customers' orders have to be delivered by: one entry for each order, destination and day, with the lines due and the deliveries that already cover them. Use it to see what is overdue, what is due soon and what has no delivery planned yet.

Read-only · scope orders.read · roles: owner, admin, sales, viewer, viewer (no pricing) · Pro and Enterprise plans

ParameterTypeRequiredDescription
fromstringNoThe first day of the window, YYYY-MM-DD. It defaults to today. Leave it out with open_only and send to alone to reach everything that is overdue.
tostringNoThe last day of the window, YYYY-MM-DD. It defaults to 30 days after from, and the window is at most 100 days.
open_onlybooleanNoLeaves out the entries that are already delivered. With to and no from it returns every open entry up to that day, the overdue ones included.
{
  "from": "2026-11-01",
  "to": "2026-11-30"
}
Example arguments

Returns: events, ordered by date. Each entry has date, sales_order_id, order_number, order_status, customer_name, customer_reference (the customer's purchase order number), destination, area, state, days_until, line_count, open_line_count, items and deliveries. Then today, from, to, open_only, summary (overdue, soon and unplanned) and truncated.

  • An entry is what one planned delivery would carry: the lines of one order going to one destination on one day, ignoring case and extra spaces in the destination's name. items lists only the first 20 lines, line_count is the total, and `sales_orders_get` shows them all.
  • A line is placed on its own due_on, or on the order's when it has none. A line with no date of its own or its order's does not appear, and neither do cancelled orders. Days are Riyadh days.
  • state is overdue (something is still open and the day has passed), upcoming, or delivered (every line has shipped on deliveries marked delivered, or the order is closed as fulfilled). days_until is negative when overdue and null once delivered. summary.soon counts what is due within 3 days.
  • area is the Saudi region the destination is in, read from its words by the first place it names: riyadh, makkah, madinah, eastern, qassim, asir, tabuk, hail, northern_borders, jazan, najran, al_bahah or al_jouf. It is null when the destination names no place the platform knows. The map on the app's delivery calendar is built on it.
  • deliveries are the non-cancelled deliveries carrying the entry's lines, drafts, scheduled and in-transit ones included. An open entry with none still needs `sales_orders_create_deliveries`, and summary.unplanned counts those entries.
  • At most 500 entries come back. If the window holds more, truncated is true: narrow the window. Entries carry no prices.

Purchase orders

A purchase order's status runs draft, sent, confirmed, partially_received and received, or ends in cancelled. Every order gets a sequential number: PO-000001, then PO-000002.

purchase_orders_list

Lists the purchase orders placed with suppliers, newest first, each with its tender and the sales order it sources. Filter by status, manufacturer, tender or sales order, or search the order number, the supplier's name or the supplier's reference.

Read-only · scope orders.read · roles: owner, admin, purchasing, viewer · Pro and Enterprise plans

ParameterTypeRequiredDescription
statusstringNoOnly orders in this status: draft, sent, confirmed, partially_received, received or cancelled.
manufacturer_idintegerNoOnly orders placed with this manufacturer from your directory.
tender_idintegerNoOnly orders sourcing this tender.
sales_order_idintegerNoOnly orders sourcing this sales order.
qstringNoText to look for in the order number, the supplier's name and the supplier's reference; it matches part of the text. Up to 200 characters.
pageintegerNoPage number, starting at 1.
page_sizeintegerNoResults per page: 20 by default, 100 at most.

Returns: A page of orders with total and total_pages. Each order carries its number, supplier, status, dates, currency, total_amount, tender and linked sales order.

  • Purchase orders are cost data: the sales, technical and viewer (no pricing) roles do not see them.

purchase_orders_get

Returns one purchase order with its lines, each showing what has been received and what remains, the receipt totals, and the manufacturer, tender and sales order linked to it.

Read-only · scope orders.read · roles: owner, admin, purchasing, viewer · Pro and Enterprise plans

ParameterTypeRequiredDescription
idintegerYesThe purchase order's ID, from purchase_orders_list.

Returns: The order in purchase_order, its lines in items (each with received_quantity and remaining_quantity), then receipt, manufacturer, tender and sales_order.

  • receipt holds ordered, received, remaining and complete. The line IDs here are the ones `purchase_orders_receive` takes.
  • An order that is not in your organization answers 404.

purchase_orders_create

Records an order placed with a supplier, with its lines. It assigns the next sequential number and starts the order as draft. The supplier is a manufacturer from your directory or a name you type, and one of the two is required.

Changes data · scope orders.write · roles: owner, admin, purchasing · Pro and Enterprise plans

ParameterTypeRequiredDescription
manufacturer_idintegerNoThe manufacturer you are ordering from, from `manufacturers_list`. The order takes its name when you leave out supplier_name. It must be in your organization's directory.
supplier_namestringNoThe supplier's name as filed, 1 to 200 characters. Required unless you send manufacturer_id.
supplier_referencestringNoThe supplier's own reference, such as their confirmation or proforma number, up to 200 characters. Send null to clear it.
tender_idintegerNoThe tender this purchase sources, from the tender tools. Send null to leave it empty.
sales_order_idintegerNoThe sales order this purchase sources goods for, from `sales_orders_list`. It must be your organization's order. Send null to leave it empty.
currencystringNoThe three-letter currency code (ISO 4217), such as SAR. Defaults to SAR, and is stored in capitals.
ordered_onstringNoThe order date, as YYYY-MM-DD. Defaults to today in Riyadh.
expected_onstringNoThe date the goods are expected, as YYYY-MM-DD. Send null to clear it.
notesstringNoNotes on the order, up to 2,000 characters. Send null to clear them.
itemsobject[]YesThe order lines, from 1 to 500.
items[].idintegerNoNot used when creating; leave it out.
items[].product_idintegerNoThe catalog product this line is for, from products_list. It must be your organization's product. Send null to remove the link.
items[].descriptionstringYesWhat was ordered, 1 to 1,000 characters.
items[].quantitynumberYesThe quantity ordered; it must be above zero.
items[].unitstringNoThe unit of measure, such as box, up to 50 characters. Send null to clear it.
items[].unit_pricenumberNoThe cost per unit in the order's currency, zero or more. Leave it out or send null while the line has no price; it then stays out of the order total.
items[].notesstringNoNotes on the line, up to 1,000 characters. Send null to clear them.
{
  "manufacturer_id": 87,
  "supplier_reference": "PI-2026-0331",
  "tender_id": 48213,
  "sales_order_id": 214,
  "expected_on": "2026-11-01",
  "items": [
    {
      "description": "Sterile syringe 5 ml, box of 100",
      "quantity": 200,
      "unit": "box",
      "unit_price": 24.8
    }
  ]
}
Example arguments

Returns: The new order's purchase_order_id and order_number.

  • When you send manufacturer_id, the order copies the manufacturer's name into supplier_name, so the order still reads after the manufacturer leaves your directory. With neither, the tool answers 400.
  • A manufacturer, sales order or product that is not your organization's, or a tender you cannot see, answers 404.
  • Every line starts with nothing received. Record arrivals with `purchase_orders_receive`.

purchase_orders_update

Changes an order's supplier, dates, links, notes or lines. Only what you send changes, and null clears an optional field. Use `purchase_orders_set_status` for the status and `purchase_orders_receive` for arrivals.

Changes data · scope orders.write · roles: owner, admin, purchasing · Pro and Enterprise plans

ParameterTypeRequiredDescription
idintegerYesThe purchase order's ID.
manufacturer_idintegerNoThe manufacturer linked to the order, from `manufacturers_list`. The order takes its name unless you also send supplier_name. Send null to unlink; the supplier name already written stays.
supplier_namestringNoThe supplier's name as filed, 1 to 200 characters.
supplier_referencestringNoThe supplier's own reference, such as their confirmation or proforma number, up to 200 characters. Send null to clear it.
tender_idintegerNoThe tender this purchase sources, from the tender tools. Send null to leave it empty.
sales_order_idintegerNoThe sales order this purchase sources goods for, from `sales_orders_list`. It must be your organization's order. Send null to leave it empty.
currencystringNoThe three-letter currency code (ISO 4217), such as SAR. Defaults to SAR, and is stored in capitals.
ordered_onstringNoThe order date, as YYYY-MM-DD.
expected_onstringNoThe date the goods are expected, as YYYY-MM-DD. Send null to clear it.
notesstringNoNotes on the order, up to 2,000 characters. Send null to clear them.
itemsobject[]NoThe complete line list, reconciled by ID (see the top of this page), from 1 to 500 lines. Leave it out to keep the lines and the total as they are.
items[].idintegerNoThe stored line's ID, from purchase_orders_get. A line sent with its ID is changed in place; a line without one is added.
items[].product_idintegerNoThe catalog product this line is for, from products_list. It must be your organization's product. Send null to remove the link.
items[].descriptionstringYesWhat was ordered, 1 to 1,000 characters.
items[].quantitynumberYesThe quantity ordered; it must be above zero.
items[].unitstringNoThe unit of measure, such as box, up to 50 characters. Send null to clear it.
items[].unit_pricenumberNoThe cost per unit in the order's currency, zero or more. Leave it out or send null while the line has no price; it then stays out of the order total.
items[].notesstringNoNotes on the line, up to 1,000 characters. Send null to clear them.
{
  "id": 98,
  "supplier_reference": "PI-2026-0331-R1",
  "expected_on": "2026-11-10"
}
Example arguments

Returns: The purchase_order_id of the updated order.

  • A line sent with its ID keeps what was received on it. Lowering its quantity below what has already arrived is refused with 400, and so is a line ID that is not on the order or is sent twice.
  • A line you leave out of the list is deleted along with what was received on it. When you send items, the total is recomputed.

purchase_orders_set_status

Moves a purchase order to a new status. Any status may follow any other, so a mistaken move can be undone. It does not touch the received quantities.

Changes data · scope orders.write · roles: owner, admin, purchasing · Pro and Enterprise plans

ParameterTypeRequiredDescription
idintegerYesThe purchase order's ID.
statusstringYesThe new status: draft, sent, confirmed, partially_received, received or cancelled.
{
  "id": 98,
  "status": "sent"
}
Example arguments

Returns: A confirmation with the new status.

  • Entering received stamps received_at, and leaving it clears the stamp. The quantities received on the lines stay as they are: moving to received by hand says the goods are in, without changing what was recorded on the lines.
  • A cancelled order takes no receipts. Move it back to draft first.

purchase_orders_delete

Deletes a purchase order together with its lines and the receipts recorded on them. This cannot be undone.

Deletes or overwrites data · scope orders.write · roles: owner, admin, purchasing · Pro and Enterprise plans

ParameterTypeRequiredDescription
idintegerYesThe purchase order's ID.

Returns: A confirmation of the deletion.

Goods receipts

When a supplier's goods arrive, record them against the purchase order's lines and the order's status moves on its own.

purchase_orders_receive

Records goods that arrived against a purchase order. Each line adds its quantity to what was already received on that line, and the order then moves to partially_received, or to received once every line is complete.

Changes data · scope orders.write · roles: owner, admin, purchasing · Pro and Enterprise plans

ParameterTypeRequiredDescription
idintegerYesThe purchase order's ID.
linesobject[]YesWhat arrived now, from 1 to 500 lines.
lines[].item_idintegerYesThe purchase order line's ID, from items in `purchase_orders_get`.
lines[].quantitynumberYesThe quantity that arrived now, above zero. It is added to the received total, not set in its place.
received_atstringNoWhen the goods arrived, as ISO 8601 with a time zone, such as 2026-10-12T09:30:00+03:00. Defaults to now. It is recorded only if this receipt completes the order.
{
  "id": 98,
  "lines": [
    {
      "item_id": 4410,
      "quantity": 120
    },
    {
      "item_id": 4411,
      "quantity": 40
    }
  ],
  "received_at": "2026-10-12T09:30:00+03:00"
}
Example arguments

Returns: A confirmation with the order's new status, and in items the new received total (received_quantity) of every line the receipt touched.

  • The whole receipt is refused, and nothing is saved, if a line names an item that is not on the order or would take a line past what was ordered. A line named twice has its quantities added together.
  • A cancelled order answers 409. Move it back to draft with `purchase_orders_set_status`, then record the receipt.
  • The order moves forward from wherever it is, draft included. received_at is recorded only once: an order already marked received keeps its date.