# Purchase Orders Purchase orders record what you have ordered from a vendor and on what terms. Each one carries vendor and ship-to details plus a list of line items drawn from your inventory. How an order moves: - `draft`, `ready_for_review` and `approved` can each move to one another, or on to `ordered` - From `ordered` you can request `voided` or `closed` - Receiving stock moves an `ordered` order to `partially_received` and then `received`, through the receive flow rather than a status call - From `partially_received` or `received`, the only status you can request is `closed` - `voided` and `closed` are final Use the status endpoint for these transitions rather than the update endpoint. ## List Purchase Orders - [GET /api/v1/purchase_orders](https://developer.sortly.com/purchase-orders/listpurchaseorders.md): Returns the company's purchase orders, most recently updated first. A listed purchase order leaves out notes, terms, sub_total and line_items, so fetch a single one for those. ## Create a Purchase Order - [POST /api/v1/purchase_orders](https://developer.sortly.com/purchase-orders/createpurchaseorder.md): Creates a purchase order. It starts in the draft status. - You don't need to send amount, sub_total, total or line_number. Sortly works them out from the lines. - Leave out purchase_order_number and Sortly generates one. - Every line needs an item_id from this company. An unknown item or unit of measure returns 404. - Use the status endpoint to move the order on. ## Fetch a Purchase Order - [GET /api/v1/purchase_orders/{purchase_order_id}](https://developer.sortly.com/purchase-orders/fetchpurchaseorder.md): Returns a single purchase order by its ID, including notes, terms, sub_total and the full line_items list that the list endpoint leaves out. ## Update a Purchase Order - [PUT /api/v1/purchase_orders/{purchase_order_id}](https://developer.sortly.com/purchase-orders/updatepurchaseorder.md): Replaces the purchase order's own fields. - Any nullable field you omit or send as null is cleared, so fetch the order first and send it back with your changes. - line_items replaces the whole list: a line with an id is updated, a line without one is added, and any stored line you leave out is removed. - On a line that already exists you cannot change item_id, name or variant_options, and lines cannot be reordered. - Only a draft, ready_for_review or approved order can be updated. Anything later returns 400. - Use the status endpoint to change status. ## Change a Purchase Order's Status - [PUT /api/v1/purchase_orders/{purchase_order_id}/status](https://developer.sortly.com/purchase-orders/changepurchaseorderstatus.md): Moves the purchase order to a new status and leaves every other field alone. - draft, ready_for_review and approved can each move to one another, or on to ordered. - From ordered you can request voided or closed. From partially_received or received, only closed. - voided and closed are final. Anything else returns 400. - received and partially_received cannot be requested here. Receiving sets them as stock arrives, which also moves an order on from ordered without a status call. - Moving to ordered records who ordered it and when, and puts the order's items on order in Sortly. - Sending the status the order already has changes nothing, so a retry is safe. ## Receive Items Against a Purchase Order - [POST /api/v1/purchase_orders/{purchase_order_id}/receive](https://developer.sortly.com/purchase-orders/receiveitemsagainstpurchaseorder.md): Records how much of the ordered quantity has arrived on the lines you name, and unless receive_config.update_strategy says otherwise adds that quantity to the matching Sortly items. Key considerations: - The work happens in the background. A successful call returns 202 straight away with the receive pending. Poll GET /api/v1/purchase_orders/{purchase_order_id}/receive/status until it reads completed or failed. - One receive at a time per order. Nothing needs carrying between the two calls; starting a second while the first is pending returns 409. - Lines can fail individually while the call succeeds. Read the ids out of received_line_item_ids and errors rather than trusting the HTTP status. - The order must be ordered or partially_received. Receiving is what moves it on to partially_received and then received, which is why neither can be set through the status endpoint. - A line must still be linked to a Sortly item, and no two lines in one request may point at the same item. ## Check Receive Status of a Purchase Order - [GET /api/v1/purchase_orders/{purchase_order_id}/receive/status](https://developer.sortly.com/purchase-orders/checkpurchaseorderreceive.md): Reports the most recent receive started against this purchase order. status is one of: - pending while lines are still being applied. Keep polling. - completed once every line went through. - failed if any of them did not. The line ids are grouped by what happened to them. Every id you sent appears in exactly one of the three, so together they account for the whole request: - received_line_item_ids for the lines that were applied - pending_line_item_ids for those the receive has not applied - errors for the ones that failed, each with its reason Two things worth knowing: - A failed receive can carry ids in pending_line_item_ids with errors empty. That is a receive that fell over before it reached those lines rather than one that rejected them, and error carries the reason. Nothing on those lines was applied. - Records are kept once a receive finishes, so this keeps reporting the last one. It returns 404 only until something has been received against the order for the first time.