Skip to content

Webhook Integration

This guide walks through setting up a webhook endpoint, verifying signatures, and handling events.

  1. Create a webhook endpoint

    Terminal window
    curl -X POST https://xqr.co/api/v1/webhooks \
    -H "Authorization: Bearer $XQR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
    "url": "https://your-app.com/webhooks/xqr",
    "events": ["link.created", "link.scanned"],
    "description": "Production webhook"
    }'

    Save the webhook id from the response.

  2. Get the signing secret

    Terminal window
    curl "https://xqr.co/api/developer/webhooks/${WEBHOOK_ID}/secret" \
    -H "Authorization: Bearer $JWT_TOKEN"

    Store this secret securely — you’ll use it to verify signatures.

  3. Implement your handler

    import crypto from "node:crypto";
    import express from "express";
    const WEBHOOK_SECRET = process.env.XQR_WEBHOOK_SECRET;
    app.post("/webhooks/xqr", express.raw({ type: "application/json" }), (req, res) => {
    // Verify signature
    const signature = req.headers["x-xqr-signature"];
    const expected = "sha256=" + crypto
    .createHmac("sha256", WEBHOOK_SECRET)
    .update(req.body)
    .digest("hex");
    if (signature !== expected) {
    return res.status(401).send("Invalid signature");
    }
    // Process event
    const event = JSON.parse(req.body);
    switch (event.event) {
    case "link.created":
    console.log("New link:", event.data.short_code);
    break;
    case "link.scanned":
    console.log("Scan from:", event.data.country);
    break;
    }
    res.status(200).send("OK");
    });
  4. Test the endpoint

    Send a test ping from the dashboard or via API:

    Terminal window
    curl -X POST "https://xqr.co/api/developer/webhooks/${WEBHOOK_ID}/test" \
    -H "Authorization: Bearer $JWT_TOKEN"
  5. Monitor deliveries

    Terminal window
    curl "https://xqr.co/api/v1/webhooks/${WEBHOOK_ID}/deliveries" \
    -H "Authorization: Bearer $XQR_API_KEY"

See also: Verifying Signatures and Retries & Failures.

Was this page helpful?