Subscribe to webhooks - Grasshopper Labs API
Webhooks

Subscribe to webhooks

Webhooks push order, item, and inventory events from Grasshopper to your systems the moment they happen. Every shipper account includes a self-service Integrations module, so your team can add, edit, and remove webhook subscriptions on its own: no code, no support ticket, and changes go live immediately.

Looking for the event list?

See Topics for every event you can subscribe to, grouped by category, plus a recommended starter set for retail integrations.

How it works

A webhook subscription pairs one event with one endpoint URL. When that event fires anywhere in the platform, Grasshopper sends an HTTP request to your URL with a JSON payload describing the order or item, plus any custom headers you configured.

  • Create one subscription per event you care about. You can point several events at the same URL; the msg_info.topic field in every payload tells you which event fired.
  • You can also register multiple endpoints for the same event, for example one per downstream system.
  • Subscriptions are scoped to your account. You only receive events for your own orders and items.

Before you start

You need three things:

  1. A shipper login with access to your account management portal.
  2. A receiving endpoint on your side: a publicly reachable HTTPS URL that accepts a JSON body and responds with a 2xx status within a few seconds.
  3. Your event list. Decide which topics you need. Most retailers start with the seven-topic starter set and expand later.

If your endpoint requires authentication, have the header name and secret value ready; you will enter them as HTTP headers on the subscription.

Add a webhook from your account

1. Open the Integrations module

Sign in to your shipper account, click the gear icon in the top navigation, and choose Integrations.

25 NK
Account
Integrations
The Integrations module lives under the gear menu in the top navigation of your shipper account.

2. Click Add New Webhook

The Webhooks panel lists every subscription on your account. If you have none yet, the panel shows only the info banner and the button.

Webhooks
Setup webhooks to allow integration and support automatic updates with other services. Read More
+  Add New Webhook
Click Add New Webhook to open a blank subscription form. The Read More link opens this guide.

3. Fill in the subscription

A new subscription form opens with three fields:

Event Name
dropdownRequired
The event this subscription listens to, for example order_status_changed. One event per webhook. The dropdown lists the full topic catalog; the Topics page describes each one.
Method
dropdownRequired
The HTTP method Grasshopper uses to call your endpoint. The form defaults to GET, but most integrations should pick POST: the event payload travels in the request body, and many frameworks discard bodies on GET requests. PUT is also supported for endpoints designed that way.
URL
stringRequired
The full URL of your receiving endpoint, for example https://hooks.acmehome.com/grasshopper. It must be publicly reachable; deliveries come from Grasshopper's servers, not from your browser.
Event Nameorder_status_changed MethodPOST URLhttps://hooks.acmehome.com/grasshopper
HTTP Headers
KeyContent-Type Valueapplication/json
Add Key/Value Pair CancelSave
A completed subscription: the order_status_changed event, delivered by POST, with a Content-Type header.

4. Add HTTP headers (optional)

Every key/value pair you add here is sent as an HTTP header on every delivery for this subscription. Use them to make the payload parse cleanly and to authenticate the calls:

  • Content-Type: application/json so your framework parses the body as JSON. Recommended for every subscription.
  • A shared-secret header such as X-Webhook-Token: your-secret-value. Your endpoint rejects any request without the expected value. See Verifying webhooks.

Click Add Key/Value Pair for additional headers, and the trash icon next to a pair to remove it.

5. Save

Click Save. The subscription is live immediately; the next time the event fires, Grasshopper calls your endpoint. There is nothing to deploy and no propagation delay.

Event Nameorder_status_changed MethodPOST URLhttps://hooks.acmehome.com/grasshopper Edit
+  Add New Webhook
Saved subscriptions are listed in the Webhooks panel. Repeat Add New Webhook for each additional event.

To test a subscription end to end before wiring in the real event, subscribe a request-inspection URL (your own staging endpoint, or a tool like a request bin) to a low-volume topic, trigger the event on a test order, and inspect what arrives.

Edit or remove a subscription

  • Edit reopens the form for that row. Change the event, method, URL, or headers, then Save. The change applies to the next delivery.
  • The trash icon at the far right of a row deletes the subscription. Deliveries for that event stop immediately. Deleting a webhook affects nothing else on your account.
Deletion is immediate and permanent

There is no undo and no confirmation grace period. Events that fire while a subscription is deleted are not delivered later if you re-create it; use the Orders API to backfill anything you missed.

Manage webhooks with the API

Everything the Integrations panel does is also exposed as REST endpoints, so you can script your webhook setup, sync it from your own admin tools, or manage it per environment in CI. Authenticate with a shipper access token, the same Authorization: Bearer flow as the rest of the API; see Authentication. Requests are scoped to the account that owns the token.

GET/api/webhook/events

Returns the full catalog of event names you can subscribe to, as a flat array of strings. This is the list behind the Event Name dropdown. The Topics page describes the ones relevant to retailer integrations.

GET/api/webhook

Lists your account's webhook subscriptions. Each entry includes _id, event, url, method, and headers. The _id value is the webhook_id used in the update and delete paths below.

POST/api/webhook

Creates a subscription. Body parameters:

event
stringRequired
Event name from the catalog, for example order_status_changed.
url
stringRequired
Full URL of your receiving endpoint.
method
stringRequired
HTTP method for deliveries: POST (recommended), GET, or PUT. Stored uppercase regardless of the case you send.
headers
array of objectsOptional
Custom headers sent with every delivery, as { "key": "...", "value": "..." } objects.
# Replace {base_url} with the host you use to sign in to your shipper account
curl -X POST "https://{base_url}/api/webhook" \
  -H "Authorization: Bearer {access_token}" \
  -H "Content-Type: application/json" \
  -d '{
    "event": "order_status_changed",
    "url": "https://hooks.acmehome.com/grasshopper",
    "method": "POST",
    "headers": [
      { "key": "Content-Type", "value": "application/json" },
      { "key": "X-Webhook-Token", "value": "whsec_9f2d41c0" }
    ]
  }'
const res = await fetch("https://{base_url}/api/webhook", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${accessToken}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    event: "order_status_changed",
    url: "https://hooks.acmehome.com/grasshopper",
    method: "POST",
    headers: [
      { key: "Content-Type", value: "application/json" },
      { key: "X-Webhook-Token", value: "whsec_9f2d41c0" }
    ]
  })
});
const { data, status } = await res.json();
import requests

res = requests.post(
    "https://{base_url}/api/webhook",
    headers={"Authorization": f"Bearer {access_token}"},
    json={
        "event": "order_status_changed",
        "url": "https://hooks.acmehome.com/grasshopper",
        "method": "POST",
        "headers": [
            {"key": "Content-Type", "value": "application/json"},
            {"key": "X-Webhook-Token", "value": "whsec_9f2d41c0"},
        ],
    },
)
data = res.json()["data"]
{
  "data": {
    "_id": "6650f2a81c9d440000a1b2c3",
    "event": "order_status_changed",
    "url": "https://hooks.acmehome.com/grasshopper",
    "method": "POST",
    "headers": [
      { "key": "Content-Type", "value": "application/json" },
      { "key": "X-Webhook-Token", "value": "whsec_9f2d41c0" }
    ],
    "createdAt": "2026-08-23T09:14:02.511Z"
  },
  "status": "ok"
}
PATCH/api/webhook/{webhook_id}/update

Updates a subscription. Send only the fields you want to change (event, url, method, headers); everything else keeps its current value.

DELETE/api/webhook/{webhook_id}/delete

Deletes a subscription. Deliveries for that event stop immediately.

What your endpoint receives

Deliveries carry a JSON body with two parts: the entity that changed (order for order events, item for line-item and inventory events) and a msg_info envelope identifying the event and the subscription that fired. A trimmed order-event example:

{
  "order": {
    "order_id": "GH-1004312",
    "status": 5,
    "service_level": "wg",
    "ref_order_number": "PO-88121",
    "customer": { ... },
    "delivery": { "scheduled_date": "2026-08-27", ... },
    "line_items": [ ... ],
    "retailer": { "_id": "63f7d2e4a9b8c700123f4a56", "identifier": "ACME" },
    "source": "webhook"
  },
  "msg_info": {
    "topic": "order_status_changed",
    "subscriber_id": "63f7d2e4a9b8c700123f4a56",
    "method": "POST",
    "webhook_id": "6650f2a81c9d440000a1b2c3"
  }
}
  • Route incoming requests on msg_info.topic, especially if several subscriptions share one URL.
  • msg_info.webhook_id tells you which subscription produced the delivery.
  • Field-by-field documentation of the order and item objects is on the Payload page. Status codes are listed under Order statuses.

Delivery and auditing

Every delivery attempt is written to the order's tracking history, visible in the portal and in the API:

  • Webhook sent, with the target URL and topic, on success.
  • Webhook failed, with the error message and your endpoint's response body, on failure.

This makes delivery debuggable without any extra tooling: open the order, read the timeline, and you can see exactly what was sent where and what your endpoint answered.

Failed deliveries are not retried

A delivery that fails is logged on the order and dropped; there is no automatic retry queue. Acknowledge with a 2xx as fast as you can and process asynchronously. If your endpoint had an outage, reconcile with the Orders API rather than waiting for a redelivery.

Best practices

  • Use POST with a Content-Type header. The payload is a JSON body; POST plus Content-Type: application/json works with every mainstream framework out of the box.
  • Serve HTTPS with a valid certificate. Payloads include customer contact details; do not receive them in the clear.
  • Authenticate every delivery. Add a secret header to the subscription and reject requests without it. Rotate the secret by editing the webhook. More in Verifying webhooks.
  • Acknowledge first, process later. Return 2xx immediately and queue the work. Slow endpoints show up as failures in the order timeline.
  • Be idempotent. Design handlers so processing the same event twice is harmless; msg_info.topic plus order.order_id plus the order's updated_at makes a good dedupe key.
  • Start small. The seven-topic starter set covers most tracking needs; add topics as your workflow grows instead of subscribing to everything on day one.
  • Keep environments separate. Webhooks are configured per account. Point your staging account at staging endpoints and your production account at production endpoints.