BigblueDevelopers

Verify your endpoint

Your endpoint must return a challenge value before Bigblue saves the webhook.

When you register a webhook in the Bigblue app, Bigblue sends a challenge to your URL. Your endpoint must return the same value. If it doesn't, the app shows "challenge failed" and the webhook isn't saved.

Challenge request

POST /webhooks/bigblue HTTP/1.1
Content-Type: application/json
X-Bigblue-Event-Type: URL_VERIFICATION
X-Bigblue-Hmac-SHA256: 5rBqz1S0K8p3xW7fT2vN9cH4mJ6dL0aY8bE1uQ3sR5k=

{ "challenge": "kdmzqrltvbxwneophjscugyafiwhqnet" }

challenge is a random string of 32 lowercase letters. The request is signed with your shared secret like every webhook request, so your endpoint must have the secret before you register it. See Verify signatures.

Expected response

Return HTTP 200 with the same value:

{ "challenge": "kdmzqrltvbxwneophjscugyafiwhqnet" }
ResponseResult
200 with the same challengeThe webhook is saved.
Any other statusFails.
200 with a different or missing challengeFails.
A body that isn't valid JSONFails.
No response, or a connection or TLS errorFails.
An http:// URLRejected before the challenge is sent.

Respond within 10 seconds

The challenge times out after 10 seconds. Normal events allow 20 seconds. If your endpoint is a serverless function, make sure it's running before you register it.

Example handlers

import express from 'express';
import crypto from 'node:crypto';

const app = express();

// Read the raw body: the signature is computed on the exact bytes.
app.post('/webhooks/bigblue', express.raw({ type: 'application/json' }), (req, res) => {
  const raw = req.body as Buffer;

  const expected = crypto
    .createHmac('sha256', process.env.BIGBLUE_WEBHOOK_SECRET!)
    .update(raw)
    .digest('base64');
  const given = req.header('X-Bigblue-Hmac-SHA256') ?? '';

  if (
    given.length !== expected.length ||
    !crypto.timingSafeEqual(Buffer.from(given), Buffer.from(expected))
  ) {
    return res.sendStatus(401);
  }

  const body = JSON.parse(raw.toString('utf8'));

  switch (req.header('X-Bigblue-Event-Type')) {
    case 'URL_VERIFICATION':
      return res.status(200).json({ challenge: body.challenge });
    case 'INVENTORY_UPDATE':
      void enqueueInventory(body);
      return res.sendStatus(200);
    case 'ORDER_STATUS_UPDATE':
      void enqueueOrderStatus(body);
      return res.sendStatus(200);
    default:
      return res.sendStatus(200);
  }
});

If registration fails

Check that:

  1. Your endpoint uses your account's current shared secret. A wrong secret makes it return 401 to the challenge.
  2. The URL uses HTTPS.
  3. The URL is reachable from the internet, without a VPN, password or IP allowlist.
  4. The endpoint returns 200. A redirect such as 301 fails, so register the final URL.
  5. The returned challenge is exactly the value you received.
  6. The response is valid JSON with Content-Type: application/json.
  7. The endpoint responds within 10 seconds.

To test the response format, send a challenge yourself:

curl -i https://hooks.example.com/webhooks/bigblue \
  -H "Content-Type: application/json" \
  -H "X-Bigblue-Event-Type: URL_VERIFICATION" \
  -d '{"challenge":"kdmzqrltvbxwneophjscugyafiwhqnet"}'

This request isn't signed, so an endpoint that checks signatures returns 401. That's expected.

On this page