Events
All webhook event types and their payload schemas.
BeeL. sends webhook events when key things happen in your account. Each event has a type field that identifies what occurred, and a data object with event-specific details.
All field names use snake_case — both in the envelope and in data payloads.
Envelope Structure
Every webhook delivery follows the same envelope format (the data block depends on the event type — see each event's section below for the exact shape):
{
"id": "3f7a1b2c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
"type": "invoice.issued",
"created_at": "2026-03-17T22:30:20.085Z",
"api_version": "2025-01",
"livemode": true,
"company_id": "9f1c2d3e-4a5b-6c7d-8e9f-0a1b2c3d4e5f",
"nif": "B12345674",
"account_id": "4d6d8dca-689a-44f4-bafc-88fa8a1bc34b",
"account_external_ref": "acct-2041",
"account_relationship": "own",
"data": { ... }
}| Field | Type | Description |
|---|---|---|
id | string (UUID) | Unique identifier for this webhook event. |
type | string | Event type (see below). |
created_at | string (ISO 8601) | Timestamp when the event was created. |
api_version | string | API version used to generate the payload. |
livemode | boolean | true for Live deliveries, false for Test. Deprecated in favour of the PROD / TEST environment vocabulary used elsewhere. |
test | boolean? | true only for test deliveries. |
company_id | string (UUID) | null | Company (NIF profile) the event is about; null when not scoped to one. A single endpoint receives events for every company it manages — route on this field. |
nif | string | null | NIF of that company. |
account_id | string (UUID) | null | Account the event happened in. |
account_external_ref | string | null | Your own identifier for that account, as supplied when you provisioned it. null for accounts you did not provision. |
account_relationship | string | null | own or managed — how account_id relates to you. null when the event is not scoped to an account. |
data | object | Event-specific payload (see below). |
Test payloads include an additional "test": true field.
account_relationship is also how you subscribe. A subscription's
account_relationship (own, managed or all, default own) decides which
accounts it receives events from — the same vocabulary you then route on. A
delivered event is always own or managed, never all.
Available Events
| Event type | Delivered when | Resource |
|---|---|---|
verifactu.status.updated | An invoice's Veri*Factu submission status changes. | Invoice |
invoice.issued | A draft invoice is issued and gets its definitive number. | Invoice |
invoice.email.sent | An invoice is emailed to its customer. | Invoice |
invoice.voided | An issued invoice is voided. | Invoice |
recurring_invoice.paused | A recurring schedule stops generating on its own. | Recurring invoice |
account.claimed | The holder of an account you provisioned takes ownership of it. | Account |
company.created | A NIF is created under an account you manage. | Company (NIF) |
representation.signed | An account holder signs the fiscal representation you requested. | Company (NIF) |
The last three are provisioner-only: they are delivered exclusively to the platform that provisioned the account, never to a subscription on any other account. See Managed accounts.
invoice.issued
Fired when an invoice is issued and finalized.
Payload
{
"id": "3f7a1b2c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
"type": "invoice.issued",
"created_at": "2026-03-17T22:30:20.085Z",
"api_version": "2025-01",
"livemode": true,
"company_id": "9f1c2d3e-4a5b-6c7d-8e9f-0a1b2c3d4e5f",
"nif": "B12345674",
"account_id": "4d6d8dca-689a-44f4-bafc-88fa8a1bc34b",
"account_relationship": "own",
"data": {
"invoice_id": "550e8400-e29b-41d4-a716-446655440000",
"invoice_number": "2025/0001",
"customer_email": "john@example.com",
"customer_name": "John Doe"
}
}data fields
| Field | Type | Description |
|---|---|---|
invoice_id | string (UUID) | The issued invoice. Required. |
invoice_number | string | Human-readable invoice number (e.g. 2025/0001). Required. |
customer_email | string | null | Customer's email address. |
customer_name | string | null | Customer's name. |
invoice.email.sent
Fired when an invoice has been successfully sent by email.
Payload
{
"id": "4a8b2c3d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
"type": "invoice.email.sent",
"created_at": "2026-03-17T22:30:20.085Z",
"api_version": "2025-01",
"livemode": true,
"data": {
"invoice_id": "550e8400-e29b-41d4-a716-446655440000",
"invoice_number": "A-2026-0026",
"all_recipients": ["john@example.com", "accounting@example.com"],
"sent_at": "2026-03-17T22:30:20.050725Z"
}
}data fields
| Field | Type | Description |
|---|---|---|
invoice_id | string (UUID) | The invoice that was sent. Required. |
invoice_number | string | null | Human-readable invoice number. |
all_recipients | string[] | All email recipients (TO + CC). Required. |
sent_at | string (ISO 8601) | Timestamp when the email was sent. Required. |
invoice.voided
Fired when an invoice is voided (anulada).
Payload
{
"id": "5b9c3d4e-6f7a-8b9c-0d1e-2f3a4b5c6d7e",
"type": "invoice.voided",
"created_at": "2026-03-17T22:31:15.000Z",
"api_version": "2025-01",
"livemode": true,
"company_id": "9f1c2d3e-4a5b-6c7d-8e9f-0a1b2c3d4e5f",
"nif": "B12345674",
"account_id": "4d6d8dca-689a-44f4-bafc-88fa8a1bc34b",
"account_relationship": "own",
"data": {
"invoice_id": "550e8400-e29b-41d4-a716-446655440000",
"invoice_number": "2025/0001",
"cancellation_reason": "Error en los datos del cliente"
}
}data fields
| Field | Type | Description |
|---|---|---|
invoice_id | string (UUID) | The voided invoice. Required. |
invoice_number | string | Human-readable invoice number. Required. |
cancellation_reason | string | null | Reason provided for the annulment. |
recurring_invoice.paused
Fired when a recurring schedule stops generating on its own — the invoice it was going to issue will not arrive. Only automatic pauses are delivered: a schedule someone paused on purpose is not news to whoever paused it.
Payload
{
"id": "7d1e5f60-8a9b-0c1d-2e3f-4a5b6c7d8e9f",
"type": "recurring_invoice.paused",
"created_at": "2026-03-18T03:00:00Z",
"api_version": "2025-01",
"livemode": true,
"company_id": "9f1c2d3e-4a5b-6c7d-8e9f-0a1b2c3d4e5f",
"nif": "B12345674",
"account_id": "4d6d8dca-689a-44f4-bafc-88fa8a1bc34b",
"account_relationship": "own",
"data": {
"recurring_invoice_id": "1c2d3e4f-5a6b-7c8d-9e0f-1a2b3c4d5e6f",
"name": "Cuota mensual mantenimiento",
"reason": "GENERATION_FAILURE",
"blocker": "NIF_NOT_REGISTERED",
"since": "2026-03-18T03:00:00Z"
}
}data fields
| Field | Type | Description |
|---|---|---|
recurring_invoice_id | string (UUID) | The schedule that stopped. Required. |
name | string | null | The schedule's name. |
reason | string | DOWNGRADE or GENERATION_FAILURE. Required. |
blocker | string | null | What blocked the emission, in the same vocabulary the emission API returns (the blockers[] of a 422 EMISSION_NOT_READY). Only for GENERATION_FAILURE. |
since | string (ISO 8601) | When it stopped. Required. |
verifactu.status.updated
Fired when the VeriFactu registration status changes. This includes:
- Initial submission (status:
PENDING) - Final acceptance by AEAT (status:
ACCEPTED) - Rejection by AEAT (status:
REJECTED)
Payload
{
"id": "6c0d4e5f-7a8b-9c0d-1e2f-3a4b5c6d7e8f",
"type": "verifactu.status.updated",
"created_at": "2026-03-07T16:20:26Z",
"api_version": "2025-01",
"livemode": true,
"company_id": "9f1c2d3e-4a5b-6c7d-8e9f-0a1b2c3d4e5f",
"nif": "B12345674",
"account_id": "4d6d8dca-689a-44f4-bafc-88fa8a1bc34b",
"account_external_ref": "acct-2041",
"account_relationship": "own",
"data": {
"invoice_id": "550e8400-e29b-41d4-a716-446655440000",
"invoice_number": "2025-001",
"verifactu_registration_id": "660e8400-e29b-41d4-a716-446655440001",
"previous_status": "PENDING",
"new_status": "ACCEPTED",
"qr_url": "https://sede.agenciatributaria.gob.es/Sede/verifactu?id=ABC123XYZ",
"qr_base64": "iVBORw0KGgoAAAANSUhEUgAAAMg...",
"invoice_hash": "B11F3A015173AD99075E2720F61E2DE1FF08CBFEDD85C6F73C77AD835301B2A3",
"error_code": null,
"error_message": null
}
}data fields
| Field | Type | Description |
|---|---|---|
invoice_id | string (UUID) | The invoice that was registered with VeriFactu. Required. |
invoice_number | string | null | Human-readable invoice number (e.g. 2025-001). |
verifactu_registration_id | string (UUID) | The VeriFactu registration record in BeeL. Required. |
previous_status | string | Status before this update. Required. |
new_status | string | Status after this update. Required. |
qr_url | string | null | AEAT verification URL. Available from PENDING status onwards. |
qr_base64 | string | null | QR code as base64-encoded PNG. Embed in invoice PDFs. |
invoice_hash | string | null | SHA-256 hash of the VeriFactu record. Present only when ACCEPTED. |
error_code | string | null | AEAT error code when new_status is REJECTED. |
error_message | string | null | Human-readable error description from AEAT. |
Null fields are omitted from the JSON payload.
Status values
previous_status and new_status share the same four-value vocabulary as an
invoice's verifactu.submission_status and the verifactu_status filter of
GET /v1/companies/{company_id}/invoices — a value
read from an event can be fed straight back into the filter. What each of the four
states means, which are terminal and which oblige you to act is on
Submission states.
Accepted example
{
"data": {
"invoice_id": "550e8400-e29b-41d4-a716-446655440000",
"invoice_number": "2025-001",
"verifactu_registration_id": "660e8400-e29b-41d4-a716-446655440001",
"previous_status": "PENDING",
"new_status": "ACCEPTED",
"qr_url": "https://sede.agenciatributaria.gob.es/Sede/verifactu?id=ABC123XYZ",
"qr_base64": "iVBORw0KGgoAAAANSUhEUgAAAMg...",
"invoice_hash": "B11F3A015173AD99075E2720F61E2DE1FF08CBFEDD85C6F73C77AD835301B2A3"
}
}Rejected example
{
"data": {
"invoice_id": "550e8400-e29b-41d4-a716-446655440000",
"invoice_number": "2025-001",
"verifactu_registration_id": "660e8400-e29b-41d4-a716-446655440001",
"previous_status": "PENDING",
"new_status": "REJECTED",
"error_code": "1105",
"error_message": "NIF del emisor no registrado en VeriFactu"
}
}account.claimed
Fired when the holder of an account you provisioned claims it — sets a password
and takes ownership. Delivered only to the provisioner that created the account.
Fetch the authoritative state with GET /v1/accounts/{account_id}.
Payload
{
"id": "8e2f6071-9b0c-1d2e-3f4a-5b6c7d8e9f0a",
"type": "account.claimed",
"created_at": "2026-03-19T09:14:02Z",
"api_version": "2025-01",
"livemode": true,
"account_id": "4d6d8dca-689a-44f4-bafc-88fa8a1bc34b",
"account_external_ref": "acct-2041",
"account_relationship": "managed",
"data": {
"account_id": "4d6d8dca-689a-44f4-bafc-88fa8a1bc34b",
"external_ref": "acct-2041",
"email": "autonomo@example.com"
}
}data fields
| Field | Type | Description |
|---|---|---|
account_id | string (UUID) | The provisioned account. Required. |
external_ref | string | Your own identifier for the account, to reconcile against your system. Required. |
email | string | null | Email of the account holder who claimed it. |
company.created
Fired when a NIF (company) is created inside an account you provisioned — typically when the holder registers their NIF on claim. Delivered only to the provisioner.
Payload
{
"id": "9f3a7182-0c1d-2e3f-4a5b-6c7d8e9f0a1b",
"type": "company.created",
"created_at": "2026-03-19T09:20:44Z",
"api_version": "2025-01",
"livemode": true,
"company_id": "550e8400-e29b-41d4-a716-446655440000",
"nif": "12345678Z",
"account_id": "4d6d8dca-689a-44f4-bafc-88fa8a1bc34b",
"account_external_ref": "acct-2041",
"account_relationship": "managed",
"data": {
"account_id": "4d6d8dca-689a-44f4-bafc-88fa8a1bc34b",
"external_ref": "acct-2041",
"nif": "12345678Z",
"company_id": "550e8400-e29b-41d4-a716-446655440000",
"legal_name": "Autónomo Example"
}
}data fields
| Field | Type | Description |
|---|---|---|
account_id | string (UUID) | The provisioned account. Required. |
external_ref | string | Your own identifier for the account. Required. |
nif | string | The NIF the holder registered. Required. |
company_id | string (UUID) | null | Identifier of the created company (NIF). |
legal_name | string | null | Registered legal/fiscal name. |
representation.signed
Fired when the fiscal (VeriFactu) representation is signed for a NIF of an account you provisioned — which is what enables production invoicing on their behalf for that NIF. Delivered only to the provisioner.
Payload
{
"id": "0a4b8293-1d2e-3f4a-5b6c-7d8e9f0a1b2c",
"type": "representation.signed",
"created_at": "2026-03-20T11:05:09Z",
"api_version": "2025-01",
"livemode": true,
"company_id": "550e8400-e29b-41d4-a716-446655440000",
"nif": "12345678Z",
"account_id": "4d6d8dca-689a-44f4-bafc-88fa8a1bc34b",
"account_external_ref": "acct-2041",
"account_relationship": "managed",
"data": {
"account_id": "4d6d8dca-689a-44f4-bafc-88fa8a1bc34b",
"external_ref": "acct-2041",
"company_id": "550e8400-e29b-41d4-a716-446655440000",
"nif": "12345678Z",
"signed_at": "2026-03-20T11:05:07Z"
}
}data fields
| Field | Type | Description |
|---|---|---|
account_id | string (UUID) | The provisioned account. Required. |
external_ref | string | Your own identifier for the account. Required. |
company_id | string (UUID) | The company (NIF) whose representation was signed. Required. |
nif | string | That NIF. Required. |
signed_at | string (ISO 8601) | When it was signed. Required. |
Headers
Every delivery carries the same set of headers whatever the event type — they are
listed in Overview, and the one you must act
on, BeeL-Signature, is covered in Signatures.
Environment Isolation
Webhook subscriptions are isolated per environment:
- Production subscriptions only receive events from production invoices (
livemode: true) - Sandbox subscriptions only receive events from sandbox invoices (
livemode: false)
Test Events
POST /v1/accounts/{account_id}/webhooks/{webhook_id}/test (or Send test event in the dashboard) fires a
synthetic payload with the same structure and an extra field:
{
"id": "...",
"type": "verifactu.status.updated",
"livemode": false,
"test": true,
"data": {
"message": "This is a test webhook from BeeL. Your endpoint is configured correctly."
}
}It is signed like any other delivery, so it also verifies your signature check. Test events are not retried if your endpoint fails to respond, and do not appear in the delivery history. See Testing your endpoint.