Skip to main content
When an event occurs, Cobalt will send a POST request to your webhook URL with a JSON payload. The payload will include information about the event that occurred.

Headers

Every webhook request includes the following headers:
HeaderDescription
cobalt-verificationHMAC-SHA256 signature of the payload for verifying authenticity
webhook-idUnique event identifier — use this to deduplicate deliveries
webhook-timestampISO 8601 timestamp of when the event was created
webhook-attemptDelivery attempt number (starting at 1)

Verifying Signatures

To ensure the webhook is coming from Cobalt, validate the cobalt-verification signature before processing the payload:
const crypto = require('crypto');

function verifySignature(payload, signature, secretKey) {
    const expectedSignature = crypto.createHmac('sha256', secretKey)
        .update(JSON.stringify(payload))
        .digest('hex');
    return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature));
}

// In your webhook handler
app.post('/webhook', (req, res) => {
    const payload = req.body;
    const signature = req.headers['cobalt-verification'];

    if (!verifySignature(payload, signature, YOUR_WEBHOOK_SECRET_KEY)) {
        return res.status(401).send('Invalid signature');
    }

    // Deduplicate using webhook-id
    const webhookId = req.headers['webhook-id'];
    if (alreadyProcessed(webhookId)) {
        return res.status(200).send('Already processed');
    }

    // Process the webhook payload
    console.log('Received valid webhook:', payload);

    res.status(200).send('Webhook received');
});

Retry Behavior

If your endpoint returns a 5xx status code or a network error occurs, Cobalt will retry delivery once (2 total attempts) with a 1-second delay. The retry uses a shorter 2-second timeout since your server should already be warm. Each retry increments the webhook-attempt header. Cobalt does not retry on:
  • 4xx status codes (except 429) — these indicate a client-side configuration issue
  • Timeouts — if your server received the request but was slow to respond, retrying could cause duplicate processing
Return a 2xx response as quickly as possible. Process the event asynchronously to avoid timeouts. If your endpoint takes longer than 5 seconds to respond, the request will time out.