Webhooks

With webhooks in Picqer, you can get push notifications when certain events happen in your Picqer account. With these webhooks, you do not need to poll the API anymore to see if a picklist is closed. You can just 'subscribe' to this event with our webhooks.

New to webhooks?

Receiving and processing webhooks is really simple. To give you a head start as a beginner, view our PHP example of a 4-line script that receives and processes a webhook.

If you are using the PHP Client, you can use the Webhook helper to easily receive webhooks.

Available events

We have a couple of events you can subscribe to. If you need an event we do not support yet, please let us know.

Comments
comments.created Triggered when a new comment is added.
Movements
movements.moved Triggered when a movement is moved and the stock is changed.
Orders
orders.created Triggered when an order is created.
orders.allocated Triggered when an order is allocated.
orders.closed Triggered when you process an order.
orders.paused Triggered when you pause an order.
orders.resumed Triggered when you resume an order.
orders.status_changed Triggered when the status of an order changes, e.g. from concept to processing or from completed to cancelled.
orders.completed Triggered when an order is completed, this is when all products are shipped to the customer.
orders.notes.created Triggered when a note is added to an order.
Picklists
picklists.created Triggered when a picklist is created.
picklists.changed Triggered when the metadata of a picklist changes. For example, changes in status, urgency, assignee, or when products on the picklist are cancelled/removed.
picklists.paused Triggered when you pause a picklist.
picklists.resumed Triggered when you resume a picklist.
picklists.closed Triggered when a picklist is closed.
picklists.cancelled Triggered when a picklist is cancelled.
picklists.shipments.created Triggered when a shipment is created on a picklist (can happen 0, 1 or multiple times per picklist).
picklists.snoozed Triggered when a picklist is snoozed.
picklists.unsnoozed Triggered when a picklist is unsnoozed, either automatically or manually.
Picklist batches
picklist_batches.created Triggered when a picklist batch is created.
picklist_batches.changed Triggered when a picklist batch is changed (excluding pick actions).
picklist_batches.completed Triggered when a picklist batch is completed.
Products
products.created Triggered when a product is added.
products.changed Triggered when a product is added or edited.
products.free_stock_changed Triggered when the free stock of a normal product is changed.
products.stock_changed Triggered when the real stock of a normal product is changed. (Do not use this for tracking of free stock changes. Use free_stock_changed for that information.)
products.assembled_stock_changed Triggered when the virtual stock of a virtual assembled product is changed.
products.stock_on_location_changed Triggered when stock on a location is changed.
products.parts.changed Triggered when parts of a product change, like added or removed parts or changes to the amount of a part.
Purchase orders
purchase_orders.created Triggered when a purchase order is created.
purchase_orders.changed Triggered when a purchase order is changed, like added or removed products.
purchase_orders.purchased Triggered when a purchase order is marked as purchased.
purchase_orders.receipts.created Deprecated: please use receipts.completed
Triggered when a purchase order receipt is created.
Receipts
receipts.created Triggered when a receipt is created.
receipts.completed Triggered when a receipt is completed and all products added to the stock.
receipts.product_received Triggered when a product for a v2 receipt is received.
receipts.product_reverted Triggered when a product for a v2 receipt is reverted.
Returns
returns.created Triggered when a return is created.
returns.changed Triggered when a return is edited, products or replacements are added.
returns.status_changed Triggered when the status of a return is changed, or when a comment/note is added.
returns.products_received Triggered when returned products for a return are received.
Stock counts
location_stock_counts.completed Triggered when a location stock count is completed.

Payload

When an event is triggered, you get a POST request on the given address. In the POST data we give information about the trigger and all data about the object involved. An example of the request we send you:

View examples of all webhook types

POST http(s)://example.com/your-endpoint
{ "idhook":228, "name":"Stock change notifications", "event":"products.free_stock_changed", "event_triggered_at":"2018-12-01 02:09:12", "data": { "idproduct":138, "idvatgroup":18, "idsupplier":null, "productcode": "6531-RB-7-9", "name": "Hyperkewl Evaporative Cooling Vest Ultra Blue 7-9yr", "price": 54.46, "fixedstockprice": 0, "productcode_supplier": "", "deliverytime": null, "description": "", "barcode": "857825001442", "type": "normal", "unlimitedstock": false, "weight": 200, "minimum_purchase_quantity": 0, "purchase_in_quantities_of": 0, "hs_code": null, "country_of_origin": null, "active": true, "tags": {}, "productfields": [], "images": [ "/files/2/cb594f30-25d0-43a6-88f2-d93e193ea316/original.jpg" ], "stock": [ { "idwarehouse":18, "stock":35, "reserved":0, "reservedbackorders":0, "reservedpicklists":0, "freestock":35, "freepickablestock":35 } ] } }
HTTP/1.1 200 OK

We expect you to give a 200 OK, 201 Created or 202 Accepted status code as a response. We ignore the content you send us. You have a maximum of 10 seconds to process the request, otherwise we also see it as a failure and we will retry.

Failures and retries

We consider the call as failed if we do not get a 200 OK, 201 Created or 202 Accepted status back from you. We will retry to send the message 15 times in the span of ~17 hours. After 15 retries we mark the call as a complete failure and delete the call from our queues.

Important: We deactivate a webhook if it keeps failing. This happens after 5 complete failures within 24 hours for the same webhook. If this happens, you can reactivate the hook by registering a new hook.

The best way to keep webhook failures to a minimum, is to store incoming webhooks in your own queue and directly respond with a 200 OK. After that you can process the webhook. Especially if you receive a lot of webhooks, this will help you a lot with limiting failures and deactivations.

Registering your hooks

Adding and removing your subscriptions to these events, or 'hooks' as we call them, is possible via the API as well as via your Picqer account. Below you find the documentation for managing your hooks via the API.

Debug logging

For easier debugging, you can see details about recent deliveries for registered webhooks in your Picqer account. Go to Settings > Webhooks to see the webhooks. On the details page you see the recent deliveries Picqer made for this webhook.

Attributes

Name Type Required Description
idhook integer generated Unique Picqer reference
name string required Your own reference for this hook
event string required The event you want subscribe to
address string required Your full endpoint for this hook, for example http://www.example.com/triggers/picqer-stock-change
secret string optional If you provide a secret key with your webhook, we will use it to sign every request so you can check the sender, see "Validating webhooks"

Get all hooks

GET https://example.picqer.com/api/v1/hooks
HTTP/1.1 200 OK [ { "idhook": 727, "name": "When picklists are created", "event": "picklists.created", "address": "http://requestb.in/1llnmzl71", "active": true, "secret": false }, { "idhook": 1922, "name": "Stock is changed", "event": "products.free_stock_changed", "address": "http://requestb.in/y7wgw6ny7", "active": true, "secret": false } ]
This endpoint uses pagination.

Get single hook

GET https://example.picqer.com/api/v1/hooks/{idhook}
HTTP/1.1 200 OK { "idhook": 1922, "name": "Stock is changed", "event": "products.free_stock_changed", "address": "http://requestb.in/y7wgw6ny7", "active": true, "secret": false }

Create new hook

Webhooks can be created at Settings > Webhooks, or you can create new webhooks via the API.

POST https://example.picqer.com/api/v1/hooks
{ "name": "Stock is changed", "event": "products.free_stock_changed", "address": "http://requestb.in/y7wgw6ny7", "secret": "my-secret-key-for-hooks" }
HTTP/1.1 201 Created { "idhook": 1922, "name": "Stock is changed", "event": "products.free_stock_changed", "address": "http://requestb.in/y7wgw6ny7", "active": true, "secret": true }

Deactivate a hook

To deactivate a hook you can use this delete call. This call will not actually delete the webhook, but it will deactivate the webhook.

DELETE https://example.picqer.com/api/v1/hooks/{idhook}
HTTP/1.1 204 No Content

Validating webhooks

If you provide a secret while registering the webhook, we will sign deliveries of the webhook with a X-Picqer-Signature header.

The signature is created with an HMAC hash, using SHA256. We use the whole body of the request as the signed content.

For example, in PHP you can check the signature as follows:

$webhookPayloadRaw = file_get_contents('php://input');
$checkingSignature = base64_encode(
        hash_hmac('sha256', $webhookPayloadRaw, 'your-provided-secret', true)
    );

$isSignatureValid = hash_equals($checkingSignature, $_SERVER['HTTP_X_PICQER_SIGNATURE']);

If you are using the PHP Client, you can use the Webhook helper to easily check the webhook signature.