Closed Loop Callbacks

Simple device callbacks, structured business callbacks, and delivery rules for Big Block integrations.

What Closed Loop Means

Closed loop callbacks let your application see what happened after Big Block drove work to a device. A callback can report a raw device event such as an acknowledgement or timeout, or a higher-level fulfillment event after a picker action changes order state.

Big Block supports two callback families. Simple device callbacks report command acknowledgements, timeouts, unsolicited idle button presses, and sequence outcomes that reuse the same acknack payload shape. Structured business callbacks report higher-level item, shipment, and order events. Both callback families use the same configured callback URL and the same callback security settings.

If you already work with webhooks, the callback URL is the same basic idea. Big Block sends an HTTP request to your endpoint when something happens, so your application gets the event immediately instead of having to keep asking whether anything changed.

Simple device callbacks

Most customers only need this callback family. It gives you direct visibility into what happened on the device with acknack results such as ack, nack, call , call_up, and call_down.

Structured business callbacks

Use these when you need stable WMS or ERP-facing events for item, shipment, and order progress. They carry an order_event field and stable business-level nonce values.

Callback Types at a Glance

Callback TypeLook ForTypical TriggerNonce To TrackBest Fit
Simple deviceacknackA device command is acknowledged or times out, or an idle button press occurs.nonce for commands, or the device's unsolicitedNonce for idle button presses.Most integrations that need direct device visibility.
Sequence stepacknackA sequence step is acknowledged or times out.The step's stepnonce appears in nonce.Per-step sequence tracking.
Sequence completeacknack = ackThe final sequence step is acknowledged.The sequence's sequencenonce appears in nonce.Whole-sequence completion detection.
Structured itemorder_eventAn order item is incremented, decremented, or acknowledged.nonce and voodoo_nonce.WMS or ERP item-level state sync.
Structured shipment or orderorder_eventA shipment or order completes.shipmentnonce or ordernonce, plus nonce and voodoo_nonce.Business-level completion tracking.

Starting the Loop

For direct device commands, closed-loop tracking starts when you send a unique transaction ID with the command. In the REST API, this field is called a nonce. Big Block later sends that value back in the simple device callback so your receiver can match the callback to the work it created.

REST API Example

import requests, json

session = requests.Session()
url = "https://www.voodoodevices.com/api/"

# Login
x = session.post(url + "user/login/",
    json={'username': 'yourusername', 'password': 'yourpassword'})
z = json.loads(x.text)

# Send command with nonce for callback tracking
session.post(
    url + "device/D4F660:AFA0CB/",
    headers={'referer': url, 'x-csrf-token': z['token']},
    json={
        'command': 'flash',
        'line1': 'Jessica',
        'line2': 'Pick 3',
        'line3': 'SKU:001256',
        'nonce': 'transactionID001',
        'seconds': 120
    }
)

How Callbacks Are Delivered

Big Block can deliver callbacks as either formatted GET requests or JSON POST requests. If your configured callback URL contains replacement fields such as {deviceid}, {nonce}, or {acknack}, Big Block formats those values into the URL and sends a GET request. If the callback URL contains no replacement fields, Big Block sends a JSON POST body instead.

{
  "acknack": "ack",
  "deviceid": "D4F660:AFA0CB",
  "location": "A1-SHELF002",
  "nonce": "transactionID001",
  "qty": 3
}

This rule applies to all callback families, including device callbacks, sequence callbacks, and order callbacks. For structured business callbacks, any field present in the callback payload can be used as a replacement field in a formatted GET URL.

Payload Fields at a Glance

PayloadExpected FieldsFast Notes
Simple device callbackacknack, deviceid, location, nonce, qtyThis is the common command or idle-button callback shape.
Sequence step callbackThe same fields as a simple device callback.The step's stepnonce is returned in nonce.
Sequence-complete callbackacknack, deviceid, location, nonce, qtyacknack = ack, deviceid = sequenceid, location = "", and qty = 0.
Structured item callbackorder_event, order, shipment, item, SKU, UPC, location, device, deviceid, quantity, ordered_quantity, quantity_fulfilled, quantity_remaining, nonce, and voodoo_nonceThis is the full item-level business state snapshot.
Structured shipment-complete callbackorder_event, order, shipment, nonce, voodoo_nonce, and shipmentnonceOnly emitted when shipment completion is configured.
Structured order-complete callbackorder_event, order, nonce, voodoo_nonce, and ordernonceOnly emitted when order completion is configured.

Callback URL Configuration

Big Block uses one configured callback URL for simple device callbacks, sequence callbacks, and structured business callbacks. The URL can be on any port, use HTTP or HTTPS, and deliver either GET or POST based on whether your URL contains replacement fields. Many programmers would describe this callback URL as a webhook endpoint.

This callback design exists to avoid polling. Polling means your application keeps sending requests such as "did anything happen yet?" on a timer. That may sound simple at first, but across many devices, orders, and active workflows it creates a large stream of repetitive requests, most of which return no useful new information.

Those extra polling requests consume CPU time, database work, and network bandwidth on both sides. As scale increases, that wasted work can slow down the server and the integration around it. Callbacks are the opposite model: Big Block only sends a request when an event actually occurs, which gives you faster updates with much less load.

Inbound Connectivity Required

When using www.voodoodevices.com, the callback is sent from Big Block's cloud server on the public Internet to the URL you provide. If that destination is a server inside your corporate firewall, most firewalls will block the connection by default because it is an inbound request from the Internet into your private network. For that reason, you must allow inbound messages from www.voodoodevices.com to reach that internal server. If your callback URL points to a public cloud endpoint instead, no firewall change is needed. If your environment cannot permit that inbound access, you may be a better fit for a self-hosted server deployment. See the Server Deployment guide.

Simple Device Callbacks

When you send a device command with a nonce, Big Block can later report the result of that command using a simple device callback. In POST callbacks, the acknack field is always lower case.

acknackMeaningWhen It Happens
ackAcknowledgedThe operator acknowledged an active command.
nackTimed OutThe command timed out before it was acknowledged.
callFront-Button CallA long front-button press while the device is idle and showing statics.
call_upPlus-Button CallA plus-button press while a multi-button device is idle and showing statics.
call_downMinus-Button CallA minus-button press while a multi-button device is idle and showing statics.

In simple command callbacks, nonce echoes the command nonce you originally sent. In unsolicited idle-button callbacks,nonce uses the device's configured unsolicitedNonce value instead.

FieldExpected Meaning
acknackThe device event result, always in lower case.
deviceidThe external device identifier.
locationThe location associated with the device.
nonceThe original command nonce, or unsolicitedNonce for idle button presses.
qtyThe quantity reported by the device at acknowledgement or timeout time.
Typical Simple POST Callback
{
  "acknack": "ack",
  "deviceid": "D4F660:AFA0CB",
  "location": "A1-SHELF002",
  "nonce": "transactionID001",
  "qty": 3
}

In this payload, qty is the quantity reported by the device at the time of acknowledgement or timeout. On multi-button devices, this can reflect quantity changes made on the device before the final acknowledgement.

Idle Buttons vs Active Commands

On multi-button devices, call_up and call_down are only generated while the device is idle and showing statics. If the plus or minus button is pressed while a command is active, Big Block treats that input as a quantity adjustment for the active command rather than as an unsolicited callback.

Lost Condition

By default, no callback is sent for a lost condition.

Sequence Callbacks

Sequences build on top of the simple device callback model. Each step in a sequence can define its own stepnonce. When a step is acknowledged or times out, Big Block emits a normal simple device callback using that step nonce as the callback nonce.

A sequence can also define a sequencenonce. After the final step is acknowledged, Big Block emits one additional sequence-complete callback. This callback is synthetic and always uses acknack = ack .

Sequence CallbackPayload ShapeHow To Read It
Step callbackThe same payload shape as a simple device callback.The step's stepnonce is returned in nonce.
Sequence-complete callbackacknack, deviceid, location, nonce, qtyacknack is always ack, deviceid is the sequenceid, location is empty, and qty is 0.
Sequence-Complete POST Callback
{
  "acknack": "ack",
  "deviceid": "SEQ003",
  "location": "",
  "nonce": "sequence-complete-003",
  "qty": 0
}

In the final sequence callback, nonce is the sequencenonce , deviceid contains the sequenceid, location is empty, and qty is 0.

No Separate Sequence NACK

There is no separate sequence-level nack callback. If a step times out, Big Block emits a normal step-level nack using that step's stepnonce, and sequence progression stops until the issue is resolved.

Order Callbacks

Orders add a second callback family: structured business callbacks. These callbacks are designed for WMS, ERP, and fulfillment integrations that need stable external identifiers and a higher-level event model than raw device acknowledgements.

order_eventMeaning
item_addedAn item's fulfilled count was incremented.
item_removedAn item's fulfilled count was decremented.
device_ackAn active order item was acknowledged through the device workflow.
shipment_fulfilledAll active item workflows in a shipment are complete.
order_fulfilledAll active item workflows in an order are complete.
Item-Level Business Callback
{
  "order_event": "device_ack",
  "order": "SO-12345",
  "shipment": "SHIP-001",
  "item": "Widget A",
  "SKU": "SKU-A",
  "UPC": "UPC-A",
  "location": "Aisle 3",
  "device": "D4F660:AFA0CB",
  "deviceid": "D4F660:AFA0CB",
  "quantity": 6,
  "ordered_quantity": 10,
  "quantity_fulfilled": 6,
  "quantity_remaining": 4,
  "nonce": "item-callback-123",
  "voodoo_nonce": "item-callback-123"
}

This payload is a state snapshot. The order_event tells you what changed, and the quantity fields tell you the current item state after that change.

FieldExpected Meaning
order_eventThe business event that changed item state.
orderThe order identifier.
shipmentThe shipment identifier.
itemThe item description or item identifier.
SKUThe SKU associated with the item.
UPCThe UPC associated with the item.
locationThe physical or logical pick location.
device and deviceidThe external device identifier, exposed under both field names.
quantityThe current fulfilled count for the item.
ordered_quantityThe requested total quantity.
quantity_fulfilledThe current fulfilled total after this event.
quantity_remainingThe open quantity remaining after this event.
nonceThe stable item callback token.
voodoo_nonceA generic alias for the same stable business nonce.
  • nonce is the stable item callback token.
  • voodoo_nonce is a generic alias for the same stable token.
  • device and deviceid both contain the external device identifier.
  • quantity is the current fulfilled count for the item.
  • ordered_quantity is the requested total.
  • quantity_fulfilled is the current fulfilled total.
  • quantity_remaining is the remaining open quantity.

Shipment and Order Completion Callbacks

Shipment and order completion callbacks are only emitted when a completion nonce is explicitly configured.

Completion CallbackExpected FieldsEmitted When
Shipment completeorder_event, order, shipment, nonce, voodoo_nonce, and shipmentnonceOnly when shipmentnonce is configured.
Order completeorder_event, order, nonce, voodoo_nonce, and ordernonceOnly when ordernonce is configured.
{
  "order_event": "shipment_fulfilled",
  "order": "SO-12345",
  "shipment": "SHIP-001",
  "nonce": "shipment-complete-001",
  "voodoo_nonce": "shipment-complete-001",
  "shipmentnonce": "shipment-complete-001"
}

If shipmentnonce is blank, Big Block does not emit shipment_fulfilled . If ordernonce is blank, Big Block does not emit order_fulfilled . This behavior lets you opt into shipment-level and order-level completion callbacks independently.

Nonce Reference

The most important distinction is that simple device callbacks use command or device nonces, while structured business callbacks use stable business-level nonces.

Nonce FieldUsed For
nonceIn simple device callbacks, this is the original command nonce or unsolicitedNonce for idle button presses.
stepnonceThe nonce used for step-level sequence callbacks.
sequencenonceThe nonce used for the final sequence-complete callback.
callback_nonceThe stable nonce configured for item-level business callbacks.
shipmentnonceThe nonce used for shipment-complete callbacks.
ordernonceThe nonce used for order-complete callbacks.
voodoo_nonceA generic alias in structured business callbacks so integrations can consume one consistent nonce field across item, shipment, and order events.

Pick the Right Identifier

If you are integrating with Orders, the safest general-purpose identifier is nonce or voodoo_nonce in the structured business callback payload. If you are integrating directly with device commands, use the simple callback nonce.

Delivery Semantics and Security

Callbacks are dispatched asynchronously. Your receiver should treat each callback as an independent event and should not assume that multiple related callbacks will arrive in a guaranteed order.

One Action Can Produce More Than One Callback

A single physical acknowledgement can generate more than one callback request. For example, if an operator acknowledges the last active item in a shipment, Big Block can emit:

  • the simple device ack callback
  • the structured device_ack item callback
  • the structured shipment_fulfilled callback
  • the structured order_fulfilled callback, if that shipment completed the entire order

For reliable integrations:

  • make your callback endpoint idempotent
  • key your processing on the appropriate nonce for the callback family
  • treat simple device callbacks and structured business callbacks as separate event streams
  • be prepared for a single picker action to fan out into multiple callback requests

Callback Security

All callback families use the same callback security configuration. Depending on your server configuration, Big Block can send callbacks with:

  • no additional security headers
  • HTTP Basic Authentication
  • an X-API-Key header
  • an OAuth bearer token for supported flows
  • an Odoo session-authenticated POST flow

These settings apply equally to simple device callbacks, sequence callbacks, and structured business callbacks.

Receiving the Callback

Your endpoint needs to accept both delivery modes. If your callback URL uses replacement fields, you will receive a GET request whose path matches your template. If your callback URL contains no replacement fields, you will receive a JSON POST body instead.

This minimal Python example prints both kinds of callbacks and branches on acknack versus order_event so you can see whether the payload is a simple device callback or a structured business callback.

from http.server import BaseHTTPRequestHandler, HTTPServer
import json

class CallbackHandler(BaseHTTPRequestHandler):

    def do_GET(self):
        print(f"GET {self.path}")
        print("Parse this path according to your configured replacement fields")
        self.send_response(200)
        self.end_headers()

    def do_POST(self):
        length = int(self.headers.get("Content-Length", 0))
        body = self.rfile.read(length)
        data = json.loads(body or b"{}")

        acknack = data.get("acknack")
        order_event = data.get("order_event")

        print(f"POST {self.path}")
        print(json.dumps(data, indent=2))

        if acknack is not None:
            print(f"Simple device callback: {acknack}")
            print(f"Simple nonce: {data.get('nonce')}")
        elif order_event is not None:
            print(f"Structured business callback: {order_event}")
            print(f"Business nonce: {data.get('nonce')}")
        else:
            print("Unknown callback payload")

        self.send_response(200)
        self.end_headers()

if __name__ == "__main__":
    server = HTTPServer(("0.0.0.0", 8000), CallbackHandler)
    print("Listening on port 8000 ...")
    server.serve_forever()

Recommended Mental Model

Use simple device callbacks when you want direct visibility into what happened on the device. Use structured business callbacks when you want stable, integration-friendly fulfillment events for items, shipments, and orders. If you are using both features at once, plan for both callback families to be active.