Handling Orders
Note
Part of the Wholesaler Integrations guide. This step assumes you have already completed Registering an Available Wholesaler — orders only arrive for clinics that have connected your wholesaler.
See Create an Order for how a
clinic places the purchase order that triggers order.placed below.
order.placed event reference
Note
This event is also published in the API reference, whose machine-readable payload schema you can generate a client from.
Provet POSTs this event to
available_wholesaler.webhook_callback_url when clinic staff send a
purchase order to a wholesaler of type Integration created from one of
your AvailableWholesaler registrations. It does not fire for
wholesalers of any other type (e.g. Email).
When the order is sent, Provet optimistically marks it as ordered and delivers this event; the payload is richer than a typical order notification so you can act on the order without follow-up calls.
Warning
order.placed may be delivered more than once for the same
order.id — either as a redundant retry of the same event
(identified by a repeated event_id, safe to drop), or as a genuinely
new event for the same order under a different event_id. The
latter doesn’t necessarily mean a brand new order was placed again —
the clinic may simply have updated the existing order. Use event_id
only to discard redundant deliveries; when a new event_id arrives
for an order.id you have already processed, compare the payload
against the version you are holding and act on whatever changed. Each
delivery carries the complete order, so the payload alone tells you
what is different.
{
"event": "order.placed",
"event_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"available_wholesaler": {"id": 7, "name": "Acme Veterinary Supplies"},
"wholesaler": {"id": 123, "customer_number": "CLINIC-42"},
"order": {
"id": 5567,
"notes": "Please deliver before noon",
"customer": {
"name": "Downtown Vet Group",
"department": "Main Clinic",
"postal_address": "12 Market Street",
"postal_code": "00100",
"city": "Helsinki",
"country_code": "FI"
},
"purchaser": {
"name": "Jane Doe",
"phone": "+358401234567",
"email": "jane.doe@downtownvet.example"
},
"items": [
{
"product_number": "ACM-001",
"product_name": "Amoxicillin 250mg",
"quantity": "12.00",
"unit": "tablet",
"barcode": "6412345678901",
"notes": null
}
]
}
}
Field |
Type |
Optional |
Meaning |
|---|---|---|---|
|
string |
No |
Always |
|
string |
No |
UUID identifying this event; stable across delivery attempts. See deduplication rules. |
|
number |
No |
ID of your registered |
|
string |
No |
Name of that |
|
number |
No |
Per-clinic |
|
number |
No |
Per-clinic |
|
object |
No |
The ordering clinic’s billing/delivery identity. |
|
object |
No |
The user who sent the order ( |
|
array |
No |
Order lines: |
|
string / null |
Yes |
The clinic’s customer number with you; department override if set, else wholesaler-global; |
|
string / null |
Yes |
Free-text note the clinic added to the order. |
Recording your own order number
When you accept an order you normally assign it a supplier order number of your own. Write it back so clinic staff can quote it to you and see it on the order:
curl -X POST \
"https://[env.]provetcloud.com/<provet_id>/api/0.1/order/<order_id>/set_wholesaler_reference_number/" \
-H "Authorization: Bearer <oauth_access_token>" \
-H "Content-Type: application/json" \
-d '{"wholesaler_reference_number": "SO123456"}'
{
"status": "ok",
"wholesaler_reference_number": "SO123456"
}
The wholesaler scope is sufficient — no additional Provet
permission is needed. The value is limited to 63 characters and appears on
the order in Provet as its Wholesaler invoice number.
Your own orders only. An order placed with a wholesaler belonging to another integration, or with no integration wholesaler behind it, is rejected with 403 (
Token does not match this wholesaler.).The order must already be placed; one still in Ordering in process is 400.
Last write wins. If the order already carries a reference number — clinic staff can enter one themselves before placing the order — yours replaces it. The response always echoes the value now stored.
The call is safe to retry: sending the same value again changes nothing and answers the same 200.
Marking an order delivered
Once you have shipped an order received via order.placed, move it out
of Ordered yourself:
curl -X POST \
"https://[env.]provetcloud.com/<provet_id>/api/0.1/order/<order_id>/mark_delivered/" \
-H "Authorization: Bearer <oauth_access_token>"
The wholesaler scope is sufficient — no additional Provet
permission is needed. The call runs exactly what the clinic’s own “Mark
products delivered” button runs:
{
"status": "ok",
"order_status": 2,
"all_delivered": true,
"delivery_date": "2026-08-12T09:15:00Z"
}
Your own orders only. An order placed with a wholesaler belonging to another integration, or with no integration wholesaler behind it, is rejected with 403 (
Token does not match this wholesaler.).The order must be in Ordered status; anything else is 400.
set_wholesaler_reference_number and mark_delivered are the only
order actions the wholesaler scope opens up. Every other order
operation stays behind the clinic’s own permissions.
Retrying a call that timed out
The call is not idempotent: it only moves an order out of Ordered, so calling it a second time on an order it already moved answers 400, not a repeat of the original success.
That makes a timed-out request safe to retry, as long as you read the failure correctly:
400 with
Order must be in 'Ordered' status to mark products delivered.— the order is no longer in Ordered, so your earlier call landed. Treat your retry as complete; there is nothing further to do.Any other 400 — a genuine failure, reporting a problem with the order’s contents. The order is still in Ordered and still awaiting delivery, so this one does need your attention. Do not treat it as success.
Concurrent duplicate calls are safe: the order row is locked for the duration, so two requests arriving together are applied one after the other, and the second gets the 400 above rather than repeating the stock changes.
Errors specific to orders
Situation |
Response |
|---|---|
|
403 |
|
400 |
|
400 |
|
400 |
See the error reference for the integration-specific errors that can occur across every phase.