Recipes
Workflows worth building, including the one that closes a gap nothing else covers.
From a form to an issued invoice
The shape most people want first: someone fills in a form and receives an invoice.
Form (NIF, name, email, concept, amount)
└─▶ store the raw request
└─▶ NIF → Validate ← real AEAT lookup
├─ invalid ─▶ end: "that NIF does not exist"
└─ valid
└─▶ Customer → Get Many (filter by NIF)
├─ found ─────────────┐
└─ not found ─▶ Create┴─▶ Merge
└─▶ Company → Issuing Readiness
├─ not ready ─▶ end: says what is missing
└─ ready ─▶ Invoice → Create
(issue_directly + send_automatically)Three details carry this workflow:
Validate the NIF first. It is one node and a real lookup against the AEAT registry — an invented NIF is rejected before anything is created.
Ask before you issue. Issuing Readiness answers whether the company can issue right now and
what is missing if not, instead of you attempting it and reading an error.
Derive the idempotency key from the submission. Two clicks on the button, or a re-run, then return the invoice that already exists rather than issuing a second one.
Store the raw form response before anything else. If a later step fails, what the customer asked for is not lost.
Sweep the charges that never became invoices
This one closes a gap nothing else covers.
The native Stripe connection invoices every charge automatically. Sometimes that fails — a missing default series, for instance. When it does, no webhook is emitted: there is no event for a payment that failed to invoice. A charge that took money without producing an invoice is only visible by asking for it: a payment with no invoice that nobody notices. It is exactly the sort of boring hourly job you do not want depending on someone remembering.
Build this one with the HTTP Request node
In the current release of the node (0.2.2), the Payment Event operations and Payment
Connection → Disconnect still address a connection by its provider, a route shape the API no
longer serves, so they fail. Until a release fixes them, call the API from an HTTP Request node
with a header credential Authorization: Bearer <your API key>. Each connection has its own ID,
which Payment Connection → Get Many returns.
Schedule (hourly)
└─▶ Payment Connection → Get Many ← gives each connection's id
└─▶ HTTP Request: GET /v1/companies/{company_id}/payment-connections/{connection_id}/events
?needs_action=true ← only the events still worth acting on
├─ retry_available ─▶ HTTP Request: POST …/events/{event_id}/retry
└─ draft_available ─▶ HTTP Request: POST …/events/{event_id}/draft + notifyEach event carries failure_category and failure_reason, plus retry_available and
draft_available telling you which recovery it accepts: retry when the cause was transient,
draft when a human should look before issuing. The full request and response are in
List payment events.
Watch for recurring invoices that stopped
Two nodes, and it prevents a quiet revenue leak.
BeeL Trigger (recurring_invoice.paused) ─▶ notify the teamBeeL. pauses a recurring invoice on its own after repeated generation failures or a downgrade. If
nobody watches that event, a monthly invoice silently stops being issued and you find out at the end
of the quarter. To resume it once fixed: Recurring Invoice → Set Status → ACTIVE.
Alert on VeriFactu rejections
BeeL Trigger (verifactu.status.updated) ─▶ if REJECTED ─▶ alertIssuing is not the same as complying. The invoice gets its number immediately, but the AEAT answers afterwards. Most integrations stop at "issued" and never learn that a submission was rejected.
Pair it with a daily sweep as a belt-and-braces: Invoice → Get Many filtered by
verifactu_status = REJECTED catches anything whose webhook delivery was lost.
Events the trigger does not offer
The BeeL Trigger lists eight events. The API sends two more that the trigger does not offer in version 0.2.2:
invoice.pdf.generated— the PDF of an invoice is ready.invoice.schedule_failed— a scheduled invoice could not be generated on its date.
To start a workflow on either one, use n8n's generic Webhook node and subscribe to it yourself:
- Add a Webhook node (method
POST) and turn on its Raw Body option. The signature is computed over the exact bytes BeeL. sent. - Create the subscription with an HTTP Request node or any client:
POST /v1/accounts/{account_id}/webhookswith the Webhook node's production URL and the events you want. See Create a webhook subscription. The response carries the signing secret, and only this once: store it in an n8n credential. - Verify the
BeeL-Signatureheader before doing anything with the payload: an HMAC-SHA256 oft, a.and the raw body, with that secret, plus the 5-minute timestamp check. The steps are in Signatures. Stop the workflow when it does not match.
The BeeL Trigger does all three for you, which is why it is the better choice for the events it lists.