BeeL.es
Product
Pricing
Pricing
← Blog
Development15 min read

How to Implement Verifactu in Your Software: Direct API, Holded, Odoo or BeeL.

Technical guide to integrating Verifactu in your application. We compare raw AEAT implementation, Holded, Odoo and BeeL.: rate limits, documentation, complexity and real cases.

April 1, 2026•
Roger Massana
Roger Massana

#The real problem: your software needs to comply with Verifactu

If you develop an ERP, a management SaaS, an invoicing app, or any software that issues invoices in Spain, you already know: since January 2026, your system must comply with the VeriFactu regulation (RD 1007/2023).

And no, “generating a nice PDF” doesn’t cut it. Your software needs to:

  • ✗Generate invoicing records with electronic signatures (SHA-256 chained hash)
  • ✗Send records to the AEAT in signed XML format
  • ✗Guarantee the immutability and traceability of each invoice
  • ✗Include a verifiable QR code on every invoice
  • ✗Maintain an internal blockchain between records

The question isn’t whether you need to do it. It’s how.

And this is where most development teams waste weeks (or months) evaluating options, fighting outdated documentation, and discovering rate limits in production that nobody warned them about.

This article is the guide we wish we’d had. We’ll compare the 4 real options you have, with their pros, cons, and real cases from clients who’ve been through this.


#The 4 options for integrating Verifactu

ℹ️Quick summary

  1. Direct implementation with AEAT — Maximum control, maximum complexity
  2. Holded API — Popular but with serious performance issues
  3. Odoo API — Open source but with very restrictive rate limits
  4. BeeL. API — Built specifically for integrators and SaaS

Let’s go one by one.


#Option 1: Direct implementation against AEAT (raw)

#What it involves

Implementing VeriFactu directly means your software communicates with the Spanish Tax Agency’s web services without intermediaries. Sounds great in theory. In practice, it’s a multi-month engineering project.

#What you need to build

  • ✗XML parser and generator following AEAT's SuministroLR schema
  • ✗Electronic signature with digital certificate (PKCS#12 / X.509)
  • ✗SHA-256 chained hash generation between records
  • ✗Submission queue system with retries and SOAP error handling
  • ✗Immutable storage of the invoicing record (not just the invoice)
  • ✗QR code generation with AEAT verification URL
  • ✗Digital certificate management (renewal, multiple companies)
  • ✗Validation against the official XSD schema
  • ✗Handling different record types: creation, cancellation, correction
  • ✗Testing against AEAT's staging environment (which has its own issues)

#The actual code you need to write

To give you an idea, this is what the XML looks like for a single invoicing record:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
                  xmlns:sii="https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SusFacturas.wsdl">
  <soapenv:Header/>
  <soapenv:Body>
    <sii:SuministroLRFacturasEmitidas>
      <sii:Cabecera>
        <sii:IDVersionSif>1.0</sii:IDVersionSif>
        <sii:Titular>
          <sii:NombreRazon>Your Company SL</sii:NombreRazon>
          <sii:NIF>B12345678</sii:NIF>
        </sii:Titular>
      </sii:Cabecera>
      <sii:RegistroFactura>
        <sii:IDFactura>
          <sii:IDEmisorFactura>B12345678</sii:IDEmisorFactura>
          <sii:NumSerieFacturaEmisor>2026/001</sii:NumSerieFacturaEmisor>
          <sii:FechaExpedicionFacturaEmisor>01-01-2026</sii:FechaExpedicionFacturaEmisor>
        </sii:IDFactura>
        <sii:PeriodoLiquidacion>
          <sii:Ejercicio>2026</sii:Ejercicio>
          <sii:Periodo>01</sii:Periodo>
        </sii:PeriodoLiquidacion>
        <!-- ... 50+ more fields -->
        <sii:Huella>
          <sii:Encadenamiento>
            <sii:PrimerRegistro>S</sii:PrimerRegistro>
          </sii:Encadenamiento>
          <sii:Hash>a1b2c3d4e5f6...</sii:Hash>
        </sii:Huella>
      </sii:RegistroFactura>
    </sii:SuministroLRFacturasEmitidas>
  </soapenv:Body>
</soapenv:Envelope>

And that’s just the submission. Then you need to handle the response, errors, retries, corrections, cancellations…

#Real problems

  • AEAT documentation: It technically exists, but it’s scattered across official gazettes, technical PDFs, and XSD schemas. There’s no modern API documentation with examples and a working sandbox.
  • Digital certificates: Each company needs its own certificate. Managing renewal, secure storage, and multi-tenancy is a project in itself.
  • Staging environment: AEAT’s test environment doesn’t always reflect production behavior. And it goes down more often than it should.
  • Development time: Based on our experience and that of clients who’ve tried it, you’re looking at 3-6 months of development for a team of 2-3 people. And that’s without counting maintenance when AEAT changes something.

⚠️Real cost

We’ve seen companies that budgeted 2 months and ended up taking 7. The complexity isn’t in sending an XML — it’s in all the edge cases: corrective invoices, cancellations, partial errors, tax ID changes, multi-series, exports…

#When it makes sense

  • You’re a large company with a dedicated development team
  • You need absolute control over every aspect of the process
  • You already have experience with AEAT web services (SII, etc.)
  • Your volume justifies the investment (thousands of invoices per day)

#Option 2: Integrating with Holded

#The promise

Holded is one of the most popular management software platforms in Spain. It has an API, it has documentation, and many companies already use it for invoicing. It seems like the obvious choice for integrating VeriFactu.

#The reality

We’ve had clients who started with Holded and ended up migrating. Not on a whim. These are the real problems they reported:

Problem 1: Rate limits that don’t scale

“We started with Holded because we were already using it internally. Everything was fine in development and with few clients. But when we hit 100 requests per minute, the system slowed down to the point of being unusable. For a SaaS with 50 active clients invoicing at the same time, 100 requests per minute is nothing.”

— Real client, SaaS company with 200+ users

100 requests per minute. Sounds like a lot until you do the math:

  • Create invoice: 1 request
  • Get customer data: 1 request
  • Validate series: 1 request
  • Confirm creation: 1 request

That’s 4 requests per invoice. At 100 req/min, you can create 25 invoices per minute. If your SaaS has 50 clients invoicing at the same time at month-end… do the math.

And when you hit the limit, it’s not a clean 429 error with a Retry-After. Performance just degrades. Requests take 10, 15, 30 seconds. Timeouts. Intermittent errors. It’s unpredictable.

Problem 2: Outdated documentation

“The API documentation says one thing, the actual behavior says another. We spent two weeks debugging a validation error because a field that the documentation marked as optional was required in production.”

We’ve heard this from more than one client. Endpoints change, fields get renamed, examples don’t work. And when you open a support ticket… the response comes in days, not hours.

Problem 3: Not an API built for integrators

Holded’s API was designed for their clients to automate their tasks. Not for a third party to build a product on top of it. This shows in:

  • No sandbox: Test against production or nothing
  • No reliable webhooks: Constant polling to detect changes
  • Limited authentication: One token per account, no OAuth, no granular scopes
  • No native multi-tenant support: If your SaaS manages 100 companies, you need 100 Holded accounts

#The hidden cost

Holded charges per user and per feature. If your model is offering invoicing as part of your SaaS, you’re paying a Holded license for each of your clients. The numbers stop making sense fast.


#Option 3: Integrating with Odoo

#The promise

Odoo is open source (Community Edition), has Spanish invoicing modules, and its XML-RPC/JSON-RPC API allows deep integrations. It seems like the “free” and flexible option.

#The reality

Problem 1: Ridiculous rate limits

The number one problem reported by those trying to use Odoo as an invoicing backend: rate limits are extremely restrictive.

On Odoo SaaS (the cloud version), depending on your plan, you may encounter limits that make any batch operation unfeasible:

  • Queries get exhausted quickly with normal operations
  • If you need to migrate data, import historical invoices, or sync in real-time with your system… prepare to wait

And if you self-host Odoo to avoid rate limits… now you have an Odoo server to maintain. With its updates, security, and performance. You’ve traded one problem for a bigger one.

Problem 2: Spanish invoicing module complexity

Odoo’s Spanish localization module (l10n_es) exists, but:

  • Not always up to date with regulatory changes: The VeriFactu regulation has very specific requirements, and community modules are slow to adapt
  • Non-trivial configuration: Correctly configuring series, tax types, withholdings, IRPF, equivalence surcharge… requires deep knowledge of both Odoo and Spanish taxation
  • Third-party modules: For full VeriFactu compliance, you’ll likely need a paid module from an Odoo partner. And those modules have their own quality, documentation, and support

Problem 3: No idempotency — duplicate invoices

This is the problem that causes the most headaches: Odoo’s API doesn’t support idempotency. There’s no Idempotency-Key or any native mechanism to prevent duplicates.

What does this mean in practice? If your invoice creation request fails due to a network timeout but Odoo actually processed it internally, retrying automatically creates a second identical invoice. And with VeriFactu, that duplicate invoice has already been sent to AEAT, with its chained hash and all. Fixing it means cancellations, corrections, and breaking the record chain.

In a SaaS processing hundreds of invoices per day, this happens more often than you’d think. Unstable connections, timeouts, automatic retries from your HTTP client… each one is a potential duplicate invoice. And discovering it after the fact, when the client already has two invoices with different numbers for the same service, is an accounting nightmare.

Problem 4: The API isn’t REST

Odoo uses XML-RPC (legacy) or JSON-RPC. It’s not REST. There’s no OpenAPI spec. No modern official SDKs.

# Creating an invoice in Odoo via XML-RPC
import xmlrpc.client
 
url = 'https://your-odoo.com'
db = 'your-database'
uid = common.authenticate(db, 'user', 'password', {})
 
# Create invoice
invoice_id = models.execute_kw(db, uid, password,
    'account.move', 'create', [{
        'move_type': 'out_invoice',
        'partner_id': 42,
        'invoice_line_ids': [(0, 0, {
            'name': 'Service',
            'quantity': 1,
            'price_unit': 100.0,
            'tax_ids': [(6, 0, [tax_id])],
        })],
    }])
 
# Confirm invoice
models.execute_kw(db, uid, password,
    'account.move', 'action_post', [[invoice_id]])

It works, but compared to a modern REST API with types, validations, and interactive documentation… it’s another era.

#When it makes sense

  • You already have Odoo deployed and your team knows it
  • Your volume is low (few invoices per day)
  • You have a trusted Odoo partner for the VeriFactu module
  • You don’t need real-time performance

#Option 4: BeeL. API

#The approach

BeeL. was designed from day 1 as an invoicing API for developers and integrators. It’s not an ERP with a bolted-on API. It’s an API with a dashboard as an additional interface.

#How VeriFactu integrates

curl -X POST https://app.beel.es/api/v1/invoices \
  -H "Authorization: Bearer your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "series": "F",
    "customer": {
      "name": "Example Client SL",
      "tax_id": "B87654321",
      "address": {
        "street": "Calle Mayor 1",
        "city": "Madrid",
        "postal_code": "28001",
        "country": "ES"
      }
    },
    "lines": [
      {
        "description": "Web development - March 2026",
        "quantity": 1,
        "unit_price": 2500.00,
        "tax_rate": 21
      }
    ]
  }'

That’s it. One request. BeeL. handles:

  • ✓Generating the SIF-compliant invoicing record
  • ✓Calculating and applying the chained SHA-256 hash
  • ✓Electronically signing the record
  • ✓Sending to AEAT automatically (VERI*FACTU mode)
  • ✓Generating the verification QR code
  • ✓Storing the record immutably

#What makes it different

Performance without artificial rate limits

There’s no 100-requests-per-minute cap. The API is designed to scale with your business. We’ve had integrators processing thousands of invoices per hour without degradation.

If your SaaS has a month-end spike because all your clients invoice at once, the API handles it. No timeouts, no degradation, no surprises.

Documentation that works

  • Complete OpenAPI 3.0 spec: Download it, import it into Postman, generate your typed client
  • Interactive documentation: Test endpoints directly from the browser
  • Real examples: Every endpoint has working request and response examples
  • Changelog: Every change documented, no surprises

Native webhooks

No polling needed. When an invoice is created, modified, or cancelled, you receive a real-time webhook:

{
  "event": "invoice.created",
  "data": {
    "id": "inv_abc123",
    "number": "F-2026/001",
    "total": 3025.00,
    "status": "confirmed",
    "verifactu_status": "sent",
    "pdf_url": "https://app.beel.es/api/v1/invoices/inv_abc123/pdf",
    "qr_verification_url": "https://..."
  },
  "timestamp": "2026-04-01T10:30:00Z"
}

Signed with HMAC-SHA256 so you can verify they come from BeeL. and not a third party.

Native multi-tenant

If your SaaS manages multiple companies, you don’t need one account per company. A single integration, multiple organizations. Each with its own certificate, series, and tax configuration.

Built for AI and automation

BeeL. exposes an llms.txt file compatible with AI agents (Claude, ChatGPT, Cursor, Copilot). Your developers can use their favorite AI tools to explore the API and generate integration code without leaving their IDE.


#Direct comparison

Raw (AEAT)HoldedOdooBeeL.
Integration time3-6 months2-4 weeks3-6 weeks1-3 days
Rate limitsNo limit (your infra)~100 req/minVery restrictiveNo artificial limits
DocumentationPDFs & official gazettesOutdatedXML-RPC docsOpenAPI 3.0 + interactive
WebhooksN/ALimitedLimitedNative + HMAC
Multi-tenantYour implementation1 account per company1 DB per companyNative
SandboxAEAT environment (unstable)NoYour instanceYes
Technical supportNoneDaysCommunity/PartnerHours
Cost for SaaSIn-house developmentPer userHosting + modulesPer usage
VeriFactu complianceYour responsibilityDepends on their implementationDepends on moduleIncluded

#Real case: migration from Holded to BeeL.

One of our current clients is a dental clinic management SaaS with over 200 clinics as users. They started using Holded’s API for invoicing.

#The problem

At month-end, when all 200 clinics generated invoices simultaneously, Holded got overwhelmed. Requests that normally took 200ms started taking 15-30 seconds. Some failed outright. And the errors weren’t consistent: sometimes timeouts, sometimes 500s, sometimes corrupted responses.

The development team spent the first day of every month firefighting instead of building new features.

#The migration

The BeeL. integration took them 3 days. Not 3 days of a full team — 3 days of a single developer. Monday: read the docs and set up the sandbox. Tuesday: migrated the integration code. Wednesday: ran tests with real data in staging.

#The result

The first month-end with BeeL.: zero incidents. Requests processed in under 300ms on average, even with all 200 clinics invoicing at once. The dev team could focus on what actually matters: improving their product.


#How to get started with BeeL. in 15 minutes

If you want to try the integration before committing, here’s what you need:

#1. Create an account and get your API key

Sign up at beel.es and generate your API key from the dashboard. No credit card required to get started.

#2. Explore the documentation

Open docs.beel.es and test endpoints directly from the browser. Or download the OpenAPI spec and import it into your favorite tool.

#3. Create your first invoice in sandbox

curl -X POST https://app.beel.es/api/v1/invoices \
  -H "Authorization: Bearer test_key_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "series": "TEST",
    "customer": {
      "name": "Test Company",
      "tax_id": "B00000000"
    },
    "lines": [
      {
        "description": "Test service",
        "quantity": 1,
        "unit_price": 100.00,
        "tax_rate": 21
      }
    ]
  }'

#4. Generate a typed client

If you use TypeScript:

npx openapi-typescript https://docs.beel.es/api/openapi -o ./beel-api.d.ts

If you use another language, openapi-generator supports 50+ languages.

#5. Set up webhooks

From the dashboard, add the URL where you want to receive events. Start with invoice.created and add more as needed.


#Frequently asked questions


#Conclusion

Integrating VeriFactu shouldn’t be a 6-month project. If your business is building software, your time should go toward improving your product, not fighting AEAT XMLs, Holded rate limits, or outdated Odoo modules.

There are options. Choose the one that fits your case:

  • Need total control and have a team? Direct implementation against AEAT
  • Already using Holded/Odoo and your volume is low? Stay where you are
  • Are you a SaaS, an integrator, or just want it to work? Try BeeL.

✅Have technical questions?

If you want to talk directly with the engineering team about your integration case, write to us at dev@beel.es. No salespeople, no 45-minute demos. Developers talking to developers.


📚Sources and References

[1] Royal Decree 1007/2023 — VeriFactu Regulation
[2] BeeL. API Documentation
[3] BeeL. OpenAPI Specification
[4] Verifactu: What It Is and How It Works

Found this useful? Share it with other freelancers

Share:

Ready to simplify your invoicing?

Join BeeL.es and comply with Verifactu hassle-free

7 days free

← View all blog posts
BeeL.es

Our best customer spends 47 seconds per month on BeeL. That's the goal.

Product

  • Blog
  • API
  • API Docs
  • Stripe
  • Accountancy demo
  • Roadmap
  • Status

Comparisons

  • Compare software
  • vs Holded
  • vs Quipu
  • vs Contasimple
  • vs STEL Order
  • vs A3Factura
  • View all →

Verifactu

  • What is Verifactu?
  • Dates and deadlines
  • Freelancer guide
  • Fines and penalties
  • Verifactu articles →
  • By city →

Community

  • LinkedIn
  • Instagram
  • TikTok
  • YouTube

Legal

  • Privacy
  • Cookies
  • Terms
  • Cancellation
  • Responsible Declaration

© 2026 BeeL.es - Made with ❤️ for freelancers like you

BeeL.es - Platja d'Aro, Girona, Spain•hola@beel.es•WhatsApp