API Reference

Purchase orders

Create and manage purchase orders via the Rebill API, from draft to sent, fulfilled or cancelled, and convert a fulfilled order into an expense.

Last updated

A purchase order is raised against a supplier for goods or services you're buying. It moves through a fixed lifecycle: draft → sent → fulfilled, with cancel available from draft or sent. A fulfilled purchase order can be converted into an expense so it shows up in your reporting.

Status values

A purchase order is always in exactly one of these statuses:

StatusDescription
draftCreated but not yet sent to the supplier. Fully editable; unnumbered
sentSent to the supplier. Supplier details are frozen; can be fulfilled or cancelled
fulfilledGoods or services have been received. Can be converted to an expense
cancelledCancelled; no further transitions

Numbering

A new purchase order is created as a draft with no number, so an abandoned draft never consumes one and leaves a gap in the sequence. A number in the form PO-0001 is allocated once, the first time it leaves draft (i.e. on send), drawn from a single account-wide counter (unlike invoices, purchase orders have no per-supplier number prefix). Re-sending an already-sent purchase order never allocates a second number.

List purchase orders

GET /purchase_order

Returns purchase orders for your account.

Query parameterTypeDescription
statusstringFilter to one status: draft · sent · fulfilled · cancelled
curl "https://api.rebill.co.za/purchase_order?status=sent" \
  -H "Authorization: Bearer sk_your_secret_key"

Get a purchase order

GET /purchase_order/:id

Returns a single purchase order by ID.

Purchase order object

FieldTypeDescription
idstringUnique identifier
public_idstringShort ID used in the public, unauthenticated supplier-facing link
numberstringSequence number in the form PO-0001; empty while still a draft
statusstringdraft · sent · fulfilled · cancelled
supplier_idstringID of the Supplier this purchase order was raised against
supplier_namestringSupplier name, frozen at send time
supplier_emailstringSupplier email, frozen at send time
supplier_addressstringSupplier address, frozen at send time
currencystringISO 4217 currency code
amountintegerTotal in cents, computed from items (including any per-line discounts)
po_datetimestampDate on the purchase order
delivery_datestringExpected delivery date (empty if unset)
itemsarrayLine items (same structure as invoice items)
notesstringFree-text notes
expense_idstringID of the Expense this purchase order was converted to, if any
createdtimestampWhen the purchase order was created

Create a purchase order

POST /purchase_order

Creates a new draft purchase order against a supplier. The supplier must exist and must not be archived.

FieldRequiredTypeDescription
supplier_idYesstringID of an existing, non-archived supplier
po_dateYesdateDate on the purchase order (YYYY-MM-DD)
itemsYesarrayAt least one line item (same structure as invoice items)
delivery_dateNodateExpected delivery date
currencyNostringISO 4217 code; defaults to your account currency
notesNostringFree-text notes
curl -X POST https://api.rebill.co.za/purchase_order \
  -H "Authorization: Bearer sk_your_secret_key" \
  -H "Content-Type: application/json" \
  -d '{
    "supplier_id": "sup_001",
    "po_date": "2026-03-20",
    "items": [
      {
        "name": "Cement (50kg bags)",
        "quantity": 20,
        "price": 15000,
        "vat_type": "standard"
      }
    ],
    "notes": "Deliver to site office"
  }'

Response (201 Created):

{
  "id": "po_001"
}

Update a purchase order

PUT /purchase_order/:id

Replaces the editable fields on a purchase order. Accepts the same fields as create. Only draft purchase orders can be updated; any other status returns 422 Unprocessable.

Delete a purchase order

DELETE /purchase_order/:id

Permanently deletes a purchase order. Only draft purchase orders can be deleted; any other status returns 422 Unprocessable.

curl -X DELETE https://api.rebill.co.za/purchase_order/po_001 \
  -H "Authorization: Bearer sk_your_secret_key"

Send a purchase order

POST /purchase_order/:id/send

Moves a draft purchase order to sent, allocates its number, freezes the supplier snapshot fields, and emails a PDF to the supplier. The supplier must have an email address, or this returns 422 Unprocessable before anything is consumed (no number is allocated on a doomed send). Only draft purchase orders can be sent.

FieldRequiredTypeDescription
pdf_base64NostringBase64-encoded PDF to attach to the email. Omit to send without a PDF attachment
skip_emailNobooleanCommit the numbering/status transition without emailing the supplier (default: false). Follow up with POST /purchase_order/:id/send_email once you have rendered a PDF from the now-numbered purchase order
curl -X POST https://api.rebill.co.za/purchase_order/po_001/send \
  -H "Authorization: Bearer sk_your_secret_key"

Send the purchase order email

POST /purchase_order/:id/send_email

Delivers the "purchase order sent" email for a purchase order that was already moved to sent via send with skip_email: true. Only a purchase order in sent status can use this endpoint. Accepts the same optional pdf_base64 field as send.

Resend the purchase order email

POST /purchase_order/:id/resend_email

Resends the email for a sent or fulfilled purchase order using its current snapshot fields and the supplier's current email address (not the frozen send-time snapshot). No status change, no renumbering. Accepts the same optional pdf_base64 field as send.

curl -X POST https://api.rebill.co.za/purchase_order/po_001/resend_email \
  -H "Authorization: Bearer sk_your_secret_key"

Fulfil a purchase order

POST /purchase_order/:id/fulfil

Marks a sent purchase order as fulfilled once goods or services have been received. Only sent purchase orders can be fulfilled.

curl -X POST https://api.rebill.co.za/purchase_order/po_001/fulfil \
  -H "Authorization: Bearer sk_your_secret_key"

Cancel a purchase order

POST /purchase_order/:id/cancel

Marks a draft or sent purchase order as cancelled. Fulfilled and already-cancelled purchase orders cannot be cancelled.

curl -X POST https://api.rebill.co.za/purchase_order/po_001/cancel \
  -H "Authorization: Bearer sk_your_secret_key"

Convert to an expense

POST /purchase_order/:id/convert_expense

Turns a fulfilled purchase order into an Expense, pre-filled from the purchase order's frozen supplier snapshot, currency, and amount. Only fulfilled purchase orders can be converted, and only once: a purchase order that has already been converted returns 409 Conflict.

FieldRequiredTypeDescription
category_idYesstringID of an existing expense category
payment_methodYesstringcash, card, bank_transfer, or other
amountNointegerAmount in cents to record on the expense; defaults to the purchase order's amount
dateNodateExpense date (YYYY-MM-DD); defaults to today
curl -X POST https://api.rebill.co.za/purchase_order/po_001/convert_expense \
  -H "Authorization: Bearer sk_your_secret_key" \
  -H "Content-Type: application/json" \
  -d '{
    "category_id": "cat-002",
    "payment_method": "bank_transfer"
  }'

Response (201 Created):

{
  "expense_id": "exp-045"
}

The created expense's supplier_id and purchase_order_id fields link it back to this purchase order and its supplier; its notes are set to "From purchase order PO-0001".

List notifications for a purchase order

GET /purchase_order/:id/notification

Returns the delivery history (email sends) recorded for this purchase order, alongside delivery/engagement state for tracked emails.

curl https://api.rebill.co.za/purchase_order/po_001/notification \
  -H "Authorization: Bearer sk_your_secret_key"

Was this article helpful?

Still need help?

Our support team is happy to help you get the most out of Rebill.

Contact support