VeriFactu submission for Stripe invoices
When invoices generated by the Stripe integration are auto-submitted to AEAT — and how to control the toggle per connection.
Stripe-generated invoices follow the same VeriFactu rules as any other invoice in BeeL, with one extra gate: the per-connection toggle. This page covers what's specific to Stripe; the underlying Auto-submit policy page explains the general behaviour.
At a Glance
| Default for Stripe connections | VeriFactu submission toggle on |
| Where to toggle | Settings > Integrations > Stripe > VeriFactu submission |
| Also needs | A VeriFactu configuration exists for your account AND its enabled flag is on |
| Submission state exposed on the invoice | Nested verifactu object — verifactu.enabled and verifactu.submission_status |
The three gates (Stripe context)
A Stripe-generated invoice is submitted to AEAT when all three of the following hold:
- The connection's VeriFactu submission toggle is on — the Stripe-specific gate
- A VeriFactu configuration exists for your account (representation signed, NIFs authorised)
- The configuration's
enabledflag is on (you haven't paused VeriFactu globally)
If any of the three is false, the invoice is still issued locally but verifactu.enabled stays false on the response — the invoice carries no submission_status, no AEAT hash, no QR. To filter for these via the API, list invoices with ?verifactu_status=NO_VERIFACTU (see the list invoices endpoint).
Why a per-connection toggle?
You may have several Stripe accounts connected to BeeL for different revenue streams. The per-connection toggle lets you submit invoices from your production account while keeping a staging account in "draft mode" (issued locally, not sent to AEAT).
It is not a way to skip VeriFactu on production payments. AEAT submission is a legal requirement for Spanish issuers once the obligation kicks in — leaving the toggle off long-term means you're issuing invoices locally that AEAT never sees.
Sandbox connections still submit. A Stripe sandbox connected to BeeL submits to AEAT's sandbox environment when the toggle is on. Real submissions only happen when both Stripe and BeeL are in production mode.
How to read the result on an invoice
The VeriFactu state is exposed as a nested verifactu object on the Invoice response. For a submitted-and-accepted invoice it looks like this:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"type": "STANDARD",
"status": "ISSUED",
"verifactu": {
"enabled": true,
"submission_status": "ACCEPTED",
"invoice_hash": "3A5B7C9D1E2F3A4B5C6D7E8F9A0B1C2D3E4F5A6B7C8D9E0F1A2B3C4D5E6F7A8B",
"registration_number": "VERIFACTU2025000001",
"qr_url": "https://verifactu.agenciatributaria.gob.es/v?id=ABC123XYZ",
"qr_base64": "iVBORw0KGgoAAAANSUhEUgAAAMgAAADI...",
"registration_date": "2026-05-18T10:24:36Z"
},
"metadata": {
"external_payment_id": "pi_3O...XYZ"
}
}When BeeL skips VeriFactu submission for the invoice (any of the three gates above is closed), the nested object collapses to { "enabled": false } and the AEAT-specific fields are absent. When AEAT rejects a submission, verifactu.submission_status is REJECTED and verifactu.error_code / verifactu.error_message carry the AEAT response. See Submission states for the full state machine.
Toggling per connection
Configure it from Settings → Integrations → Stripe → pick connection → VeriFactu submission switch. The toggle is dashboard-only today — there's no public endpoint to read or modify it programmatically.
What to do with invoices stuck in NO_VERIFACTU
The public API does not expose an endpoint to manually trigger a submission for an invoice that landed in NO_VERIFACTU after the fact. Your options:
- Fix the gate going forward. Flip the connection's VeriFactu submission switch on (or enable VeriFactu globally), and every subsequent Stripe payment will submit automatically. Already-issued invoices stay as they were.
- Bulk backfill. For a wave of historical invoices, write to it@beel.es with the invoice IDs or date range.
To find affected invoices via the API, list with verifactu_status: NO_VERIFACTU — see the list invoices endpoint.
What happens on rejection
AEAT can still reject a Stripe-generated invoice — most commonly because of:
- NIF receptor not in census — the customer's tax ID isn't registered. Pre-validate via NIF validation, or accept the invoice will be issued as F2.
- Chain integrity error — internal; open a ticket.
- Importe mismatch — should be impossible thanks to Fiscal Mirror; if you see this, the Stripe charge had a quirk worth investigating.
Handle the rejection like any other rejection — see Cancel vs amend.
Related
- Auto-submit policy — full policy detail
- Submission states — the lifecycle after submission
- Edge cases and limits — what to do when the submission keeps failing