Skip to content

The purchase-order model

Concepts

Two closely related shapes exist:

  • PurchaseOrder — what you read in OrderStatus.result (the stored extraction, with AIOTIC's additive fields).
  • ErpPurchaseOrder — what your ERP receive endpoint gets (a fixed subset, with operator corrections applied).

Both follow the same rules: every key is always present, optional values are null (never omitted), dates are ISO YYYY-MM-DD, amounts are decimal numbers, quantities are whole numbers.

PurchaseOrder (in result)

json
{
  "order_number": "EB2500011645",
  "order_date": "2026-01-14",
  "delivery_date": "2026-02-01",
  "delivery_date_from": null,
  "delivery_date_to": null,
  "supplier": { "company": "Acme Supplies BV", "contact_person": null, "email": "orders@acme.example",
                "address": { "street": "Industrieweg 5", "postal_code": "1234 AB", "city": "Amsterdam", "country": "NL" } },
  "customer": { "customer_id": "58931", "company": "LUMITECH INSTALLATIES", "contact_person": "J. de Boer",
                "email": "info@lumitech.example", "phone": "+31 55 123 4567", "branch": null,
                "vat_id": "NL001234567B01", "iban": null, "bic": null,
                "address": { "street": "Ambachtsweg 12", "postal_code": "7327 AA", "city": "Apeldoorn", "country": "NL" } },
  "shipping_details": { "recipient": { "company": "LUMITECH INSTALLATIES", "contact_person": "J. de Boer", "department": null,
                        "email": null, "phone": null,
                        "address": { "street": "Ambachtsweg 12", "postal_code": "7327 AA", "city": "Apeldoorn", "country": "NL" } },
                        "special_instructions": null },
  "items": [
    { "article_number": "PROD-001", "customer_item_number": "LT-ART-001", "description": "LED Driver 48V",
      "quantity": 10, "quantity_state": "Valid", "unit": "ST", "price": 12.34, "currency": "EUR", "line_total": 123.40 }
  ],
  "total_price": 123.40,
  "currency": "EUR",
  "additional_information": null
}
FieldTypeNotes
order_numberstringThe customer's PO number. / is replaced by - (many ERPs cannot store it).
order_datestringISO date where the document allowed it.
delivery_datestring | nullThe single date your ERP consumes. When the document states a window, AIOTIC collapses it to one end according to the tenant's preference (earliest by default).
delivery_date_from / delivery_date_tostring | nullThe window bounds, for audit. null for single-date orders.
currencystring | nullISO code as printed (EUR).
total_pricenumber | nullThe printed document total — may include VAT. When e-mail instructions changed the lines, this is the recalculated net sum and the original total is noted in additional_information.
additional_informationstring | nullFree text from document and e-mail, plus notes AIOTIC appends.

Supplier

supplier is you. It is pinned from tenant configuration and identical on every order; it is not extracted from the document. Do not map it — it is there so the payload is self-describing.

Customer

FieldNotes
customer_idYour customer (debtor) number, exactly as you synced it via PUT /customer/{number}. null when AIOTIC could not identify the sender with confidence — the order is then in ATTENTION.
company, address, email, phone, vat_idWhen a customer was identified with high confidence, these are canonicalised from your master record; otherwise they are as read from the document.
branchThe issuing branch/location named on the document (chains with one debtor per branch).
iban, bicRarely present on purchase orders; passed through when found.

Shipping details

shipping_details.recipient is the ship-to block. When the document has no explicit one, AIOTIC fills it from the identified customer. special_instructions carries delivery remarks ("deliver before noon").

Line items

FieldNotes
article_numberYour SKU, after resolution through the catalog and customer item mappings (how). null = unresolved → ATTENTION.
customer_item_numberThe customer's own code as printed, when present. Useful to create a mapping afterwards.
quantityWhole units. null only when quantity_state is Unrecognised. Lines with a blank or zero quantity (assortment listings) are dropped before storage.
quantity_stateValid, Unrecognised (kept for review), or absent on older orders.
unitAs printed (ST, PCS, Stk, m, KG…). Map it on your side (SDK sanitizer).
price, line_totalUnit price and line amount as printed, when present.

ErpPurchaseOrder (what your endpoint receives)

The hand-off payload is a fixed allow-list of the above:

  • header: order_number, order_date, delivery_date, currency, total_price, additional_information, supplier
  • customer: customer_id, company, contact_person, email, phone, iban, bic, vat_id, address{street, postal_code, city, country}
  • shipping_details.recipient: company, department, contact_person, email, phone, address{…} and special_instructions
  • items[]: article_number, description, quantity, unit, price, currency, line_total

Not included: quantity_state, customer_item_number, branch, delivery_date_from/to. Operator edits from the AIOTIC app are merged in before sending. The full JSON Schema is in the API reference.

Working with it in Python

python
from aiotic.models import ErpReceiveRequest, PurchaseOrder

req = ErpReceiveRequest.model_validate_json(body)      # in your receive endpoint
for line in req.purchase_order.items:
    ...

status = client.orders.get(request_id)                  # when polling
po: PurchaseOrder | None = status.result
if po and po.unresolved_items:
    ...

Documentation revision 3 · Published 8 September 2026 · commit 6862d5e. Verified against AIOTIC API v1.0.0. AIOTIC is a product of DevOps Company.