Skip to content

Outbound: webhooks

API reference

Calls AIOTIC makes to you. You implement these endpoints; AIOTIC authenticates with the key you provided. Guide: The ERP receive endpoint · The processing webhook.

ERP receive endpoint — implemented by you

POST<your URL>X-API-KEY (your key)

AIOTIC calls this URL (configured per tenant as the ERP API URL) when an operator — or an API caller via POST /erp/send/{request_id} — sends a reviewed order to the ERP.

  • Method POST, Content-Type: application/json, header X-API-KEY: <key you gave us>.
  • Respond within the tenant's timeout (default 30 s) with a JSON body carrying success.
  • request_id is stable across retries: make the handler idempotent (return the same order_number if you already created the order for this id).
  • Return success: false with a clear error for business rejections (unknown article, blocked customer, …); the text is shown to the operator in AIOTIC.

Header X-API-KEY — The key you provided during onboarding

Request bodyapplication/json

Body AIOTIC POSTs to your ERP receive endpoint.

FieldTypeRequiredDescription
request_idstringyesAIOTIC's order id (UUID). Stable across retries of the same send — use it as the idempotency key and store it on your sales order as external reference. Format: uuid.
purchase_orderErpPurchaseOrderyesThe reviewed purchase order with operator corrections applied. Every key below is always present; unknown values are null.

Example:

json
{
  "request_id": "550e8400-e29b-41d4-a716-446655440000",
  "purchase_order": {
    "order_number": "EB2500011645",
    "order_date": "2026-01-14",
    "delivery_date": "2026-02-01",
    "currency": "EUR",
    "total_price": 1234.56,
    "additional_information": "Please deliver before noon.",
    "supplier": {
      "company": "Acme Supplies BV",
      "contact_person": "P. Jansen",
      "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",
      "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",
        "department": null,
        "contact_person": "J. de Boer",
        "email": null,
        "phone": null,
        "address": {
          "street": "Ambachtsweg 12",
          "postal_code": "7327 AA",
          "city": "Apeldoorn",
          "country": "NL"
        }
      },
      "special_instructions": null
    },
    "items": [
      {
        "article_number": "PROD-001",
        "description": "LED Driver 48V",
        "quantity": 10,
        "unit": "ST",
        "price": 12.34,
        "currency": "EUR",
        "line_total": 123.4
      }
    ]
  }
}

Every field of the hand-off payload

Every key listed here is always present; "nullable" means the value may be null.

PathTypeNullableDescription
request_idstringAIOTIC's order id (UUID). Stable across retries of the same send — use it as the idempotency key and store it on your sales order as external reference.
purchase_orderobjectThe reviewed purchase order with operator corrections applied. Every key below is always present; unknown values are null.
purchase_order.order_numberstringThe customer's purchase-order number as printed, with / replaced by -. Map it to the "your reference" / external document number of the sales order.
purchase_order.order_datestringyesOrder date as an ISO YYYY-MM-DD string where the document allowed it; otherwise as printed.
purchase_order.delivery_datestringyesRequested delivery date (YYYY-MM-DD) or null. When the document stated a window it is already collapsed to a single date.
purchase_order.currencystringyesCurrency code as printed on the document (e.g. EUR) or null.
purchase_order.total_pricenumberyesThe document's printed total, which may include VAT, or the recalculated net sum when e-mail instructions changed lines. Informational — let your ERP compute totals.
purchase_order.additional_informationstringyesFree text from the document and e-mail plus notes AIOTIC appends (e.g. the original printed total after a recalculation).
purchase_order.supplierobjectyesYour own company as configured for the tenant — identical on every order, never read from the document. Safe to ignore.
purchase_order.supplier.companystringYour company name as configured for the tenant.
purchase_order.supplier.contact_personstringyesContact person configured for the tenant, if any.
purchase_order.supplier.emailstringyesOrder intake e-mail address of the tenant.
purchase_order.supplier.addressobjectYour company address as configured.
purchase_order.supplier.address.streetstringStreet and house number.
purchase_order.supplier.address.postal_codestringPostal code.
purchase_order.supplier.address.citystringCity.
purchase_order.supplier.address.countrystringyesCountry code as printed, usually ISO 3166-1 alpha-2.
purchase_order.customerobjectThe identified customer (debtor). customer_id is your customer number; the address block is canonicalised from your master record on a confident match.
purchase_order.customer.customer_idstringyesYour customer (debtor) number as synced via PUT /customer/{number}. null only when an operator explicitly sent an unidentified order.
purchase_order.customer.companystringyesCustomer company name.
purchase_order.customer.contact_personstringyesPerson who placed this order, as printed on the document (document-authoritative, not the master record).
purchase_order.customer.emailstringyesCustomer e-mail address.
purchase_order.customer.phonestringyesCustomer phone number.
purchase_order.customer.ibanstringyesBank account when printed on the order; usually null.
purchase_order.customer.bicstringyesBank identifier when printed on the order; usually null.
purchase_order.customer.vat_idstringyesVAT registration number.
purchase_order.customer.addressobjectCustomer (bill-to) postal address.
purchase_order.customer.address.streetstringyesStreet and house number.
purchase_order.customer.address.postal_codestringyesPostal code as printed or as stored in your master record.
purchase_order.customer.address.citystringyesCity.
purchase_order.customer.address.countrystringyesCountry code as printed, usually ISO 3166-1 alpha-2.
purchase_order.shipping_detailsobjectShip-to recipient and delivery instructions. Filled from the customer block when the document has no explicit delivery address.
purchase_order.shipping_details.recipientobjectThe ship-to block.
purchase_order.shipping_details.recipient.companystringyesShip-to company name.
purchase_order.shipping_details.recipient.departmentstringyesDepartment or address line 2.
purchase_order.shipping_details.recipient.contact_personstringyesShip-to contact for the carrier.
purchase_order.shipping_details.recipient.emailstringyesShip-to e-mail.
purchase_order.shipping_details.recipient.phonestringyesShip-to phone.
purchase_order.shipping_details.recipient.addressobjectDelivery address.
purchase_order.shipping_details.recipient.address.streetstringyesStreet and house number.
purchase_order.shipping_details.recipient.address.postal_codestringyesPostal code as printed or as stored in your master record.
purchase_order.shipping_details.recipient.address.citystringyesCity.
purchase_order.shipping_details.recipient.address.countrystringyesCountry code as printed, usually ISO 3166-1 alpha-2.
purchase_order.shipping_details.special_instructionsstringyesFree-text delivery instructions ("deliver before noon", dock number).
purchase_order.items[]array of objectsOne entry per order line, in document order. Lines without an ordered quantity (assortment listings) are already dropped.
purchase_order.items[].article_numberstringyesYour article number (SKU) after resolution through your catalog and customer item mappings. null only on an explicit override send of an unresolved line.
purchase_order.items[].descriptionstringyesLine description as printed by the customer.
purchase_order.items[].quantityintegeryesOrdered quantity in whole units. null only when the quantity was unreadable and an operator overrode the review.
purchase_order.items[].unitstringyesUnit of measure as printed (ST, PCS, Stk, m, KG, …) — map it to your ERP's codes.
purchase_order.items[].pricenumberyesUnit price as stated by the customer, or null.
purchase_order.items[].currencystringyesLine currency, normally equal to the header currency.
purchase_order.items[].line_totalnumberyesLine amount as printed (quantity × price), or null.

Expected response

Outcome (any HTTP status is accepted; the body decides)

Body your ERP receive endpoint must return. success is authoritative — AIOTIC ignores the HTTP status for the business outcome (a 500 with success: false and a success: true with 200 are both handled correctly; a non-JSON body is treated as a server error).

FieldTypeRequiredDescription
successbooleanyes
order_numberstringYour ERP's reference for the created order; stored as erp_ref and shown to operators
errorstringHuman-readable reason when success is false; shown to operators

Accepted:

json
{
  "success": true,
  "order_number": "SO-2026-00981"
}

Business rejection:

json
{
  "success": false,
  "error": "Unknown article number: PROD-999"
}

Processing webhook (optional) — implemented by you

POST<your URL>X-API-KEY (your key)

If the tenant has the processing webhook enabled, AIOTIC POSTs the extracted order to this URL as soon as extraction finishes — before any operator review, and regardless of whether the order landed in PROCESSED or ATTENTION.

Use it as an early signal ("an order arrived, here is the AI's reading"), not as the hand-off: the reviewed, corrected version reaches you through the ERP receive endpoint.

  • Header X-API-KEY: <configured value>; respond 2xx to acknowledge.
  • Delivery is best-effort: no retries and no signature today (see the proposal appendix in the guide).

Request bodyapplication/json

Body of the optional processing webhook, sent when extraction completes (before any human review).

FieldTypeRequiredDescription
request_idstringyesFormat: uuid.
purchase_orderPurchaseOrderyes

Every field of the webhook payload

Every key listed here is always present; "nullable" means the value may be null.

PathTypeNullableDescription
request_idstring
purchase_orderobjectThe extracted purchase order as returned in OrderStatus.result. Every field is always present; optional fields are null, never omitted.
purchase_order.order_numberstringCustomer's PO number. / is replaced by -.
purchase_order.order_datestringISO 8601 date (YYYY-MM-DD) where the document allowed it
purchase_order.delivery_datestringyesSingle requested delivery date (resolved from a window per tenant preference)
purchase_order.delivery_date_fromstringyesLower bound when the document states a delivery window
purchase_order.delivery_date_tostringyesUpper bound when the document states a delivery window
purchase_order.supplierobjectThe receiving company — your company. Pinned from tenant configuration, not extracted per document.
purchase_order.supplier.companystringYour company name as configured for the tenant.
purchase_order.supplier.contact_personstringyesContact person configured for the tenant, if any.
purchase_order.supplier.emailstringyesOrder intake e-mail address of the tenant.
purchase_order.supplier.addressobjectYour company address as configured.
purchase_order.supplier.address.streetstringStreet and house number.
purchase_order.supplier.address.postal_codestringPostal code.
purchase_order.supplier.address.citystringCity.
purchase_order.supplier.address.countrystringyesCountry code as printed, usually ISO 3166-1 alpha-2.
purchase_order.customerobjectyesThe identified customer (debtor). customer_id is your customer number and is set only when AIOTIC resolved the customer with confidence.
purchase_order.customer.customer_idstringyes
purchase_order.customer.companystring
purchase_order.customer.contact_personstringyes
purchase_order.customer.emailstringyes
purchase_order.customer.phonestringyes
purchase_order.customer.branchstringyesIssuing branch / location named on the document, when any
purchase_order.customer.vat_idstringyes
purchase_order.customer.ibanstringyes
purchase_order.customer.bicstringyes
purchase_order.customer.addressobject
purchase_order.customer.address.streetstringStreet and house number.
purchase_order.customer.address.postal_codestringPostal code.
purchase_order.customer.address.citystringCity.
purchase_order.customer.address.countrystringyesCountry code as printed, usually ISO 3166-1 alpha-2.
purchase_order.shipping_detailsobjectyes
purchase_order.shipping_details.recipientobjectThe ship-to block.
purchase_order.shipping_details.recipient.companystringShip-to company name.
purchase_order.shipping_details.recipient.contact_personstringyesShip-to contact for the carrier.
purchase_order.shipping_details.recipient.departmentstringyesDepartment or address line 2.
purchase_order.shipping_details.recipient.emailstringyesShip-to e-mail.
purchase_order.shipping_details.recipient.phonestringyesShip-to phone.
purchase_order.shipping_details.recipient.addressobjectDelivery address.
purchase_order.shipping_details.recipient.address.streetstringStreet and house number.
purchase_order.shipping_details.recipient.address.postal_codestringPostal code.
purchase_order.shipping_details.recipient.address.citystringCity.
purchase_order.shipping_details.recipient.address.countrystringyesCountry code as printed, usually ISO 3166-1 alpha-2.
purchase_order.shipping_details.special_instructionsstringyesFree-text delivery instructions.
purchase_order.items[]array of objectsOne order line as stored on the order (result.items[]).
purchase_order.items[].article_numberstringyesYour (supplier-side) article number, resolved through the catalog and customer mappings where possible
purchase_order.items[].customer_item_numberstringyesThe customer's own article number as printed, when present
purchase_order.items[].descriptionstringyes
purchase_order.items[].quantityintegeryesOrdered quantity in whole units; null when unreadable (see quantity_state)
purchase_order.items[].quantity_statestringyesWhat the quantity column literally showed. Unrecognised rows keep an empty quantity and put the order in ATTENTION.
purchase_order.items[].unitstringyesUnit of measure as printed (e.g. ST, PCS, KG)
purchase_order.items[].pricenumberyesUnit price
purchase_order.items[].currencystringyes
purchase_order.items[].line_totalnumberyes
purchase_order.total_pricenumberyes
purchase_order.currencystringyes
purchase_order.additional_informationstringyesFree text from the document / e-mail, plus audit notes AIOTIC appends (e.g. original document total)

Expected response

Acknowledged

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