Agent skill

Bringg Webhooks Skill

Receive and authenticate Bringg delivery orchestration webhooks. Use when setting up a Bringg webhook endpoint, securing it with Static Headers authentication, debugging 401s on Bringg webhooks, or handling webhook_type events such as task_created, task_done, task_cancelled, driver_assigned, way_point_arrived and note_created.

Install this skill

npx skills add hookdeck/webhook-skills --skill bringg-webhooks


Bringg POSTs JSON to your URL when an order, driver or route event occurs. Bringg webhooks are not signed: there is no HMAC and no timestamp. You authenticate them with a secret header that you add to the webhook as a Static Header (a Key-Value pair), and you route them by the webhook_type field in the body.

When to Use This Skill

  • How do I receive Bringg webhooks?
  • How do I authenticate Bringg webhooks with Static Headers?
  • Does Bringg sign webhook requests? (No: use a secret header)
  • How do I handle task_created, task_done or driver_assigned events?
  • Why does my Bringg webhook endpoint return 401?

Verification (core)

The header name is whatever Key you chose, so read it from config. Compare the whole header value (including any Bearer prefix you typed) in constant time. Don't parse or strip it.

const crypto = require('crypto');

// Hash both sides: equal-length buffers, so timingSafeEqual never throws.
function safeEqual(a, b) {
  const ha = crypto.createHash('sha256').update(String(a)).digest();
  const hb = crypto.createHash('sha256').update(String(b)).digest();
  return crypto.timingSafeEqual(ha, hb);
}

function verifyBringgRequest(headers, config = process.env) {
  const secret = config.BRINGG_WEBHOOK_SECRET;
  if (!secret) return false;                    // never accept when unconfigured
  const name = (config.BRINGG_WEBHOOK_HEADER || 'Authorization').toLowerCase();
  const received = headers[name];               // Node lowercases header names
  return typeof received === 'string' && received !== '' && safeEqual(received, secret);
}

Python: hmac.compare_digest(received.encode(), secret.encode()) (bytes on both sides; str raises on non-ASCII). Return 401 on a missing header or mismatch, 400 for a body that isn't a JSON object, 200 once handled. Read the body raw (express.raw({ type: '*/*' }) in Express) so any content type works, and parse JSON only after the credential check.

A static shared credential authenticates the sender, not the body, and gives no replay protection (no signature, no timestamp). Use HTTPS only, and rotate the credential in Bringg if it leaks. Bringg also supports JWT and OAuth 2.0 authentication for webhooks; those need custom code and are not covered here.

For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.

Event Types

Every body has a webhook_type. The examples handle:

webhook_typeSent When
task_createdA new order is created
task_doneAn order is completed
task_cancelledAn order is cancelled
driver_assignedAn order is assigned to a driver
way_point_arrivedA driver arrives at a way point (destination)
note_createdA note, photo, signature or form is added to an order (Order Attachment Created)

See references/overview.md for more events and the Webhooks Index link.

Environment Variables

BRINGG_WEBHOOK_HEADER=Authorization             # Key of the Static Header (case-insensitive)
BRINGG_WEBHOOK_SECRET=Bearer replace-with-token # exact whole Value, including any "Bearer "

Local Development

Bringg can't reach localhost. Tunnel with the Hookdeck CLI (no account required):

npx hookdeck-cli listen 3000 bringg --path /webhooks/bringg

Use the printed URL as the webhook URL in Bringg and add your static header there.

Resources


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Nov 3, 2026

View on GitHub →