Purchase orders

Purchase orders to a vendor. A proposal is status: "proposal", the same shape as an AR quote. ponumber is assigned under a lock when omitted.

The object#

FieldTypeDescription
idread-onlyintegerNolaPro id.
vendoridintegerReference to vendors, by id. Write either this or vendor.
vendorstring(30)Code for the referenced vendor, instead of the id.
ponumberstring(20)The customer's purchase order number.
duedatestringDate payment is due.
locationidintegerInventory location to receive into.
locationstring(20)The locationcode of the referenced inventorylocations, instead of the id. Send this or locationid, not both unless they agree.
carrierserviceidintegerCarrier service the purchase order ships by.
carrierservicestring(100)Code for the referenced carrierservice, instead of the id.
tracknumberstring(255)Carrier tracking number.
contactstring(20)Vendor contact for the purchase order.
requisitionstring(22)Requisition reference.
ordernumberstring(20)Order # of the sales order this PO buys for, when the PO was pulled from an order.
completeinteger1 when the PO is complete - fully received or manually closed; no further receipts are expected.
cancelbooleanCancelled. Always a boolean on the wire, whatever integer width the column uses (D23).
entrydatestringWhen the record was created.
lastchangedateread-onlystringLast modification. Drives modifiedsince.
referenceidintegerReferenceid. Id only.
notestextNotes. Stored as text, no practical length limit.
initialsstring(255)Buyer initials shown on the PO.
statusstringA proposal is the PO version of a quote - one field flip converts it. Partial and Complete are not statuses: see effectivestatus and complete. Stored as int -1/0; never exposed (D35). One of proposal, open.
effectivestatusread-onlystringWhat the PO list screen shows. partial is computed from whether receipts exist - it is not stored, so it cannot be written; sending it is rejected like any read-only field. One of proposal, open, partial, complete.
descriptionstring(255)Purchase order description.
wherefromintegerWhere the PO originated; 0 for POs entered on the purchase order screen.
salesordernumberstring(20)Sales Order Number reference shown on the PO.
dropshipinteger1 when the PO drop-ships from the vendor directly to the customer.
shiptoidintegerShiptoid. Id only.
salesorderidintegerSalesorderid. Id only.
paytermsidintegerPaytermsid. Id only - the table this points at is not identifiable from the column name, so there is no human key to send instead.
paytermsstring(30)Code for the referenced invoiceterms, instead of the id.
ccpurchaseidintegerCcpurchaseid. Id only.
stageidintegerStageid. Id only.
recipient_useridintegerUser who will receive the goods.
recipient_userstring(50)The name of the referenced genusers, instead of the id. Send this or recipient_userid, not both unless they agree.
jobidintegerJobid. Id only.
totaltaxmoneystring(5dp)Stored as decimal(19,5).
main_invpoidintegerMain invpoid. Id only.
prior_invpoidintegerPrior invpoid. Id only.
retainagemoneystring(2dp)Stored as decimal(12,2).
fobstring(2)FOB terms printed on the PO.
chargebackinteger1 when the PO is charged back to another vendor.
chargeback_vendoridintegerVendor the chargeback PO is charged back to.
chargeback_vendorstring(30)The vendorcode of the referenced vendors, instead of the id. Send this or chargeback_vendorid, not both unless they agree.
chargeback_invpoidintegerChargeback invpoid. Id only.
chargeback_percentnumberstring(2dp)Numeric string, 2 decimal places. Not money - do not apply currency rounding.
pototalmoneystring(6dp)Stored as decimal(19,6).
currencystring(10)Currency the PO is priced in.
curratenumberstring(10dp)Numeric string, 10 decimal places. Not money - do not apply currency rounding.
taxratenumberstring(2dp)Numeric string, 2 decimal places. Not money - do not apply currency rounding.
costcodeidintegerCost code.
costcodestring(20)Code for the referenced costcode, instead of the id.
glcategoryidintegerGlcategoryid. Id only.
glcategorystring(20)The code of the referenced glcategories, instead of the id. Send this or glcategoryid, not both unless they agree.
return_from_invpoidintegerReturn from invpoid. Id only.
rtvnumberstring(45)RTV number, for a return-to-vendor PO.
vendor_orderfromidintegerVendor orderfromid. Id only.
address1string(100)Street address.
address2string(100)Second address line.
citystring(50)City of the PO ship-to address.
completedatestringDate the PO was completed.
customerdropshiptoidintegerCustomer ship-to address a drop-ship PO delivers to.
customerdropshiptostring(30)The customercode of the referenced customers, instead of the id. Send this or customerdropshiptoid, not both unless they agree.
donotupdatelastpocostbooleanTrue keeps receipts on this PO from updating the item’s last PO cost (Do Not Update Last PO Cost).
headernotetextHeadernote. Stored as text, no practical length limit.
prepaidintegerPrepaid. Id only.
shipnamestring(50)Ship To name printed on the PO.
statestring(20)State of the PO ship-to address.
zipstring(15)Postal code.
addressverifiedread-onlystring(32)Hash of the address as it stood when it last passed the AvaTax/USPS address check; when it no longer matches the current address the address counts as unverified. Maintained by the verification flow, so it cannot be written through the API.
externalidstring(100)Your own key. Scoped to your company.

Endpoints#

POST/purchaseorders/batch 207400422

Create many.

Requires scope purchaseorders:write.

Parameters
NameInTypeNotes
Body array
FieldTypeDescription
vendoridrequiredintegerWho the order is placed with.
numberstring(20)PO number. Leave it out and NolaPro allocates the next one - which is the normal case.
datestringOrder date. Defaults to today.
duedatestringWhen it is wanted. Defaults to the order date.
locationidintegerInventory location to receive into.
descriptionstring(255)Free text on the order.
notestextLonger notes.
requisitionstring(22)Requisition reference.
ordernumberstring(20)Your order number.
tracknumberstring(255)Carrier tracking number.
externalidstring(100)Your own identifier for this record. Stored verbatim and returned on reads; GET /<resource>?externalid=... finds it again.
linesrequiredarray of objectAt least one line. pototal and the line numbers are derived - do not send them.
When it fails
StatusCodeMeaning
400invalid_requestThe request was malformed.
422rule_violationNolaPro refused the document. message carries its reason.
422unknown_valueA reference did not resolve in this company.
curl -X POST \
  'https://acme.nolapro.com/!/api/v2/purchaseorders/batch' \
  -H 'Authorization: Bearer $NP_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: your-unique-key' \
  -d '[
    {
        "vendorid": 104,
        "date": "2026-08-02",
        "duedate": "2026-08-02",
        "externalid": "crm-8842",
        "lines": [
            {
                "quantity": "3.000000",
                "price": "125.0000"
            }
        ]
    }
]'
Response 207
{
    "results": [
        {
            "index": 1,
            "status": 1
        }
    ]
}
GET/purchaseorders 200403

List purchase orders.

Requires scope purchaseorders:read.

Parameters
NameInTypeNotes
statusquerystringRestrict to one status. One of: proposal, open.
completequerystringRestrict to one complete.
vendoridquerystringRestrict to one vendorid.
locationidquerystringRestrict to one locationid.
jobidquerystringRestrict to one jobid.
descriptionquerystringdescription. Partial match, case-insensitive.
ponumberquerystringPartial match, case insensitive.
cancelquerystringDefaults to false. Pass true or any.
modifiedsincequerystringRFC 3339 UTC timestamp. Returns only records changed since then, including cancelled ones - so cancel defaults to any rather than false when this is used. The response carries _meta.synced_through; store it and send it back next time.
externalidquerystringExact match on your own key.
includequerystringComma-separated extras to embed. Only custom_fields is available: the extra fields this install has defined on the record. Off by default, and an unrecognised value is refused rather than ignored. See Conventions.
When it fails
StatusCodeMeaning
403insufficient_scopeToken lacks read scope.
curl \
  'https://acme.nolapro.com/!/api/v2/purchaseorders' \
  -H 'Authorization: Bearer $NP_TOKEN'
POST/purchaseorders 201400422

Create.

Creates a purchase order, optionally with its lines. Omit ponumber to have one assigned from the ponumberseq sequence under a lock.

Requires scope purchaseorders:write.

Parameters
NameInTypeNotes
Body
FieldTypeDescription
vendoridrequiredintegerWho the order is placed with.
numberstring(20)PO number. Leave it out and NolaPro allocates the next one - which is the normal case.
datestringOrder date. Defaults to today.
duedatestringWhen it is wanted. Defaults to the order date.
locationidintegerInventory location to receive into.
descriptionstring(255)Free text on the order.
notestextLonger notes.
requisitionstring(22)Requisition reference.
ordernumberstring(20)Your order number.
tracknumberstring(255)Carrier tracking number.
externalidstring(100)Your own identifier for this record. Stored verbatim and returned on reads; GET /<resource>?externalid=... finds it again.
linesrequiredarray of objectAt least one line. pototal and the line numbers are derived - do not send them.
When it fails
StatusCodeMeaning
400invalid_requestA required field was missing.
422rule_violationNolaPro refused the document. message carries its reason.
422unknown_valueA reference did not resolve in this company.
curl -X POST \
  'https://acme.nolapro.com/!/api/v2/purchaseorders' \
  -H 'Authorization: Bearer $NP_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: your-unique-key' \
  -d '{
    "vendorid": 104,
    "date": "2026-08-02",
    "duedate": "2026-08-02",
    "externalid": "crm-8842",
    "lines": [
        {
            "quantity": "3.000000",
            "price": "125.0000"
        }
    ]
}'
Response 201
{
    "status": "quote"
}
GET/purchaseorders/{id} 200404

Retrieve one record.

Requires scope purchaseorders:read.

Parameters
NameInTypeNotes
idrequiredpathintegerThe record id.
includequerystringComma-separated extras to embed. Only custom_fields is available: the extra fields this install has defined on the record. Off by default, and an unrecognised value is refused rather than ignored. See Conventions.
When it fails
StatusCodeMeaning
404not_foundNo record with that id.
curl \
  'https://acme.nolapro.com/!/api/v2/purchaseorders/104' \
  -H 'Authorization: Bearer $NP_TOKEN'
Response 200
{
    "status": "proposal",
    "effectivestatus": "proposal"
}
PATCH/purchaseorders/{id} 200400404409422

Update.

Only the fields you send change. Children cannot be sent here - lines are create-only (see Conventions). Use the child resource to add, change or remove one. Changing status from quote to open commits inventory for every line and is reported back as an inventory_committed warning.

Requires scope purchaseorders:write.

Parameters
NameInTypeNotes
idrequiredpathintegerThe record id.
Body
FieldTypeDescription
duedatestringWhen payment or delivery is expected.
descriptionstring(255)Free text.
notesstring(500)Longer notes.
requisitionstring(22)Requisition reference.
ordernumberstring(20)Your order number.
tracknumberstring(255)Carrier tracking number.
externalidstring(100)Your own identifier for this record.
When it fails
StatusCodeMeaning
400invalid_requestThe request was malformed.
404not_foundNo such record, or it belongs to another company.
409line_has_receiptsThe purchase order has receipts against it.
409po_completeThe purchase order is marked complete.
409stale_recordIf-Match did not match; someone else changed it first.
422rule_violationNolaPro refused the change. message carries its reason.
curl -X PATCH \
  'https://acme.nolapro.com/!/api/v2/purchaseorders/104' \
  -H 'Authorization: Bearer $NP_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: your-unique-key' \
  -d '{
    "duedate": "2026-08-01",
    "description": "Example description",
    "notes": "Example notes",
    "requisition": "Example requisition",
    "ordernumber": "INV-88421",
    "tracknumber": "INV-88421"
}'
DELETE/purchaseorders/{id} 200400409422

Cancel.

Requires scope purchaseorders:cancel.

Parameters
NameInTypeNotes
idrequiredpathintegerThe record id.
When it fails
StatusCodeMeaning
400invalid_requestThe request was malformed.
409cannot_cancelSomething already depends on this document - a payment, a shipment, an invoice.
409line_has_receiptsThe purchase order has receipts against it.
422unknown_valueNo such record in this company.
curl -X DELETE \
  'https://acme.nolapro.com/!/api/v2/purchaseorders/104' \
  -H 'Authorization: Bearer $NP_TOKEN'
GET/purchaseorders/{id}/pdf 200

Purchase order as a PDF

The purchase order as it is sent to the vendor. Answers application/pdf, not JSON. Because the body is binary it cannot be carried inside a /batch results array; asking for it there returns 415 not_batchable.

Requires scope purchaseorders:read.

Parameters
NameInTypeNotes
idrequiredpathintegerThe record id.
curl \
  'https://acme.nolapro.com/!/api/v2/purchaseorders/104/pdf' \
  -H 'Authorization: Bearer $NP_TOKEN'
GET/purchaseorders/{id}/checklist 200

Receiving checklist as a PDF

The receiving checklist for the order: what to expect and tick off as it arrives. Carries no costs, because it goes to the dock. Answers application/pdf, not JSON. Because the body is binary it cannot be carried inside a /batch results array; asking for it there returns 415 not_batchable.

Requires scope purchaseorders:read.

Parameters
NameInTypeNotes
idrequiredpathintegerThe record id.
curl \
  'https://acme.nolapro.com/!/api/v2/purchaseorders/104/checklist' \
  -H 'Authorization: Bearer $NP_TOKEN'