I’m not receiving webhooks
Symptom
You registered a webhook, but your endpoint never receives PinBridge deliveries, or receives some and then stops.
Causes and fixes
1. Only two events exist
PinBridge emits exactly two webhook events: pin.published and pin.failed. Any other event name you subscribe to (for example schedule.created or asset.uploaded) will never fire, because those are activity-log actions, not webhook events. Make sure your webhook subscribes to pin.published and/or pin.failed.
2. The webhook is not enabled
A webhook only delivers when it is enabled (is_enabled). Confirm it is on:
curl -H "X-API-Key: $PINBRIDGE_API_KEY" \
"https://api.pinbridge.io/v1/webhooks"
If is_enabled is false, update the webhook to enable it.
3. Your endpoint must return 2xx
A delivery counts as successful only if your endpoint returns an HTTP 2xx status. Any other status (or a network error) is treated as a failure and retried.
- Respond
200(any 2xx) as soon as you receive the payload. - Do your processing after responding, not before, so slow work does not cause a timeout.
4. Respond within the timeout
Each attempt has a 30-second timeout. If your endpoint takes longer, the attempt is counted as failed. Acknowledge fast, process async.
5. Retries are finite
Failed deliveries are retried up to 5 attempts with exponential backoff (roughly 2, 4, 8, 16 minutes after the first attempts). After that the delivery is marked permanently failed and will not be retried. If your endpoint was down for a while, expect to miss those deliveries; fix the endpoint before the retries run out.
6. Signature mismatch
If you verify signatures (recommended) and your check fails, you may be rejecting valid deliveries. PinBridge signs with HMAC-SHA256 over the raw JSON request body only (no timestamp), and sends the hex digest in the X-PinBridge-Signature header. Also sent: X-PinBridge-Event (the event type) and X-PinBridge-Delivery-ID.
To verify:
- Compute
HMAC-SHA256(secret, raw_body)and hex-encode it. - Compare against
X-PinBridge-Signatureusing a constant-time comparison. - Use the raw request bytes, not a re-serialized JSON object. Re-serializing changes the bytes and breaks the signature.
- There is no timestamp in the signed string; do not expect a Stripe-style
t=...,v1=...header.
The secret is set when you create the webhook (16 to 255 characters, required). If you rotate it, update your verifier too.
7. Payload shape
Only these fields are sent, and the event type is in the header, not the body:
// pin.published
{ "pin_id": "...", "pinterest_pin_id": "...", "title": "...", "published_at": "..." }
// pin.failed
{ "pin_id": "...", "error_code": "...", "error_message": "..." }
If your handler expects a top-level event or timestamp field in the body, that is why it looks empty. Read the event type from X-PinBridge-Event.
Related
- My pin failed — the
pin.failedpayload carries the sameerror_code. - Error reference — 422 errors when creating a webhook (secret and URL rules).
- Troubleshooting — all articles.
