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" }| Response | Result |
|---|---|
200 with the same challenge | The webhook is saved. |
| Any other status | Fails. |
200 with a different or missing challenge | Fails. |
| A body that isn't valid JSON | Fails. |
| No response, or a connection or TLS error | Fails. |
An http:// URL | Rejected 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:
- Your endpoint uses your account's current shared secret. A wrong secret makes
it return
401to the challenge. - The URL uses HTTPS.
- The URL is reachable from the internet, without a VPN, password or IP allowlist.
- The endpoint returns
200. A redirect such as301fails, so register the final URL. - The returned
challengeis exactly the value you received. - The response is valid JSON with
Content-Type: application/json. - 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.