Webhooks

Overview

Receive real-time notifications in your application when events happen in BeeL.


Webhooks let your application receive HTTP notifications the moment something happens in BeeL. — no polling required. When an event occurs (e.g. AEAT processes a VeriFactu submission), BeeL. sends an HTTP POST to the URL you registered with a signed JSON payload.

Developer Plan exclusive: Webhooks are available only with the Developer Plan. See Pricing for details.

Quick Start

1. Create a webhook subscription

curl -X POST "https://app.beel.es/api/v1/webhooks" \
  -H "Authorization: Bearer beel_sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourapp.com/webhooks/beel",
    "events": ["invoice.emitted", "invoice.email.sent", "invoice.cancelled", "verifactu.status.updated"]
  }'

The response contains a secret field — copy it now. It will not be shown again.

{
  "success": true,
  "data": {
    "id": "3f7a1b2c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
    "url": "https://yourapp.com/webhooks/beel",
    "events": ["invoice.emitted", "invoice.email.sent", "invoice.cancelled", "verifactu.status.updated"],
    "active": true,
    "secret": "whsec_a3f5b2e1c9d8f7e6b5a4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2",
    "created_at": "2026-03-08T10:00:00Z"
  }
}

Store the secret securely! It's only shown once and required to verify webhook signatures.

2. Handle incoming requests

Your endpoint must:

  • Accept POST requests with Content-Type: application/json
  • Verify the signature using the BeeL-Signature header
  • Return HTTP 2xx within 10 seconds
// Express.js example
app.post('/webhooks/beel', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['beel-signature'];

  if (!verifySignature(req.body, signature, process.env.BEEL_WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  const event = JSON.parse(req.body);

  switch (event.type) {
    case 'invoice.emitted':
      handleNewInvoice(event.data);
      break;
    case 'invoice.email.sent':
      handleEmailSent(event.data);
      break;
    case 'invoice.cancelled':
      handleCancellation(event.data);
      break;
    case 'verifactu.status.updated':
      handleVeriFactuUpdate(event.data);
      break;
  }

  res.status(200).send('OK');
});

3. Test your endpoint

Use the Send test event button in the BeeL. dashboard (Developers → Webhooks → your webhook) to fire a synthetic payload to your endpoint immediately.

Don't have an endpoint yet? Use webhook.site to get a free temporary URL that captures and displays incoming requests. It's a great way to inspect webhook payloads and verify that events are being delivered correctly before building your handler.


Payload Structure

Every webhook event shares the same envelope:

{
  "id": "3f7a1b2c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
  "type": "verifactu.status.updated",
  "created_at": "2026-03-07T16:20:26Z",
  "api_version": "2025-01",
  "livemode": true,
  "test": null,
  "data": { ... }
}
FieldTypeDescription
idstring (UUID)Unique event ID. Stays the same across all retry attempts.
typestringEvent type identifier (e.g. invoice.emitted).
created_atstring (ISO 8601)When the event was generated.
api_versionstringAPI version used when the event was created (2025-01).
livemodebooleanfalse for Sandbox API keys.
testboolean?true only for test deliveries triggered from the dashboard.
dataobjectEvent-specific payload. See Events.

Limits

ParameterValue
Max subscriptions per account10
Max active subscriptions10
Required URL schemehttps://
Timeout per delivery attempt10 seconds
Max delivery attempts5 (1 original + 4 retries)
Delivery log historyLast 50 per subscription

Headers Sent on Every Delivery

HeaderDescription
Content-Typeapplication/json
BeeL-SignatureHMAC-SHA256 signature — see Signatures
BeeL-EventEvent type (e.g. invoice.emitted)
BeeL-Event-IdUUID identifying this logical event. Identical across all retry attempts. Matches the id field in the payload.
BeeL-Delivery-IdUUID unique to this specific delivery attempt. Matches the delivery log id in the dashboard.
Idempotency-KeySame value as BeeL-Event-Id — for automatic deduplication by frameworks

Using Official SDKs (Coming Soon)

Our official SDKs will include built-in webhook verification:

Node.js

import { WebhookVerifier } from '@beel_es/sdk';

const verifier = new WebhookVerifier(process.env.BEEL_WEBHOOK_SECRET);

app.post('/webhooks/beel', express.raw({ type: 'application/json' }), (req, res) => {
  try {
    const event = verifier.verify(
      req.body.toString('utf8'),
      req.headers['beel-signature']
    );
    
    // Event is verified and typed
    if (event.type === 'verifactu.status.updated') {
      console.log('Invoice:', event.data.invoice_number);
      console.log('Status:', event.data.new_status);
    }
    
    res.status(200).send('OK');
  } catch (error) {
    res.status(400).send('Invalid signature');
  }
});

Java

import es.beel.sdk.webhook.WebhookVerifier;

WebhookVerifier verifier = new WebhookVerifier(System.getenv("BEEL_WEBHOOK_SECRET"));

@PostMapping("/webhooks/beel")
public ResponseEntity<String> handleWebhook(
    @RequestBody String rawBody,
    @RequestHeader("BeeL-Signature") String signature
) {
    try {
        var event = verifier.verify(rawBody, signature);
        // Event is verified
        return ResponseEntity.ok("OK");
    } catch (WebhookVerificationException e) {
        return ResponseEntity.status(400).body("Invalid signature");
    }
}

See the SDKs documentation for more details.


What's Next

  • Events — Available event types and their data payloads
  • Signatures — Verify that requests come from BeeL.
  • Retries — How failed deliveries are retried
  • Deduplication — Safely handle duplicate deliveries

Questions? Email us at it@beel.es.