NewConnections and customer replies to invoices
BeeL
Get startedMulti-NIFVeriFactuRulesStripeAPI referenceChangelog

Testing VeriFactu in sandbox

How VeriFactu behaves in sandbox — always on, registered against AEAT's test environment, no representation to sign — and the few ways it differs from Live.


Sandbox runs the same VeriFactu flow as Live — issue, submit, PENDING, AEAT's answer, QR, cancellation — against AEAT's test environment instead of the real one. Nothing you issue there is a real invoice, and nothing reaches the real AEAT registry.

Access, cost and time limits

  • Access. Sign up at app.beel.es/signup and create a key with the beel_sk_test_ prefix — see API keys. No card is needed.
  • Cost. Free. Only production is billed, and sandbox invoices never count towards a plan's invoices — see Pricing.
  • Time limit. None: the sandbox does not expire.
  • Limits. The same rate limits as production, and a lower email quota — in sandbox, email only goes to your own address (Sending email). BeeL.'s Terms reserve the right to set usage limits on the sandbox.

Can I build the whole integration in sandbox?

Yes. The base URL, the endpoints and the responses are the same as in production; only the key changes. The one exception is the NIF validation endpoint, which answers with simulated data. Everything else that checks a NIF still uses the real AEAT census in sandbox, see below. You can create NIFs, issue every invoice type, correct and void, receive webhooks and follow each VeriFactu record through AEAT's test environment.

Two things can only be done in Live, because they have no test mode: signing the representation of a NIF, and the billing of a NIF switched on in Live. Going live is switching the NIF on in Live, signing its representation and swapping the key — see Enabling VeriFactu for a NIF.

What is different from Live

SandboxLive
VeriFactuAlways on. Every invoice of the NIF is submittedOn only once you enable it
Turning it offNot possible — enabled: false returns 422 VERIFACTU_ALWAYS_ON_IN_SANDBOXPUT … { "enabled": false }
RepresentationNot needed — there is nothing to authoriseMust be signed before enabling
NIF registrationDone for you, asynchronouslyDone in the enabling call
Where submissions goAEAT's test environmentAEAT
QR codePoints to AEAT's test validation servicePoints to AEAT's validation service
NIF validation endpoint (/nif/validate)Simulated. Only the syntax is checked; the AEAT register is not queriedChecked against the AEAT register
Creating a company or a customer, issuingChecked against the real AEAT censusChecked against the AEAT census

NIF validation is simulated

POST /v1/nif/validate does not query the AEAT register in sandbox. It still checks the syntax, so you can exercise every branch of your flow:

  • A well-formed NIF comes back VALID, with the legal_name you sent, legal_name_verified: false and no census_status.
  • A malformed NIF, or one with a wrong control character, comes back INVALID, as in Live.

To check a NIF against the real register, call the endpoint with a Live key. This applies to API keys and to the MCP server connected to Test.

The census is real everywhere else

Only /nif/validate is simulated. Creating a company, creating a customer and issuing check the NIF against the real AEAT census in sandbox too, so use real NIFs. For an individual, AEAT checks the NIF together with the name: a NIF that is not in the census and a name that does not match it get the same answer from AEAT, so both are 422 NIF_VALIDATION_INVALID when creating a company.

VeriFactu is always on

In sandbox enabled is a constant of the mode, not a decision: the configuration always reads enabled: true, and every invoice you issue there goes through the full VeriFactu cycle. That is deliberate — the point of the sandbox is to exercise the path your Live integration will take.

The NIF registers itself

You don't enable anything in sandbox, so BeeL. registers the NIF in AEAT's test environment on its own — when the NIF is switched on in Test, and again on its first submission if that earlier attempt did not go through.

Because that registration travels asynchronously, nif_status can read DEACTIVATED or null for a short while after you start, even though enabled is already true. It does not block you: issuing in sandbox does not wait for it. If nif_status stays that way after your first invoice has been submitted, contact support.

Where the submission goes

Submissions go to AEAT's test environment, so the whole lifecycle is real — AEAT validates the record and answers — but nothing is registered for real. The qr_url of a sandbox invoice points to AEAT's test validation service (for example https://prewww2.aeat.es/wlpl/TIKE-CONT/ValidarQR?…), not the production one. Don't print a sandbox QR on a document you hand to a customer.

Timings in the test environment can be slower than in Live; a cancellation, for instance, can take a few minutes to reach VOIDED.

ENV_MISMATCH

A NIF operates in each environment separately. If you call with a test key for a NIF that is switched on only in Live, issuing is blocked with ENV_MISMATCH, and GET /v1/companies/{company_id}/issuing-readiness lists it as a blocker. Switch the NIF on in Test with the activations endpoint — free and immediate — or use the key of the environment where it is active.

A Stripe test account is not a sandbox submission

Whether an invoice goes to AEAT's test environment is decided by the NIF and environment you issue under, not by the Stripe account that paid. A payment from a Stripe test account does not, on its own, make the resulting invoice a test submission. See Stripe / VeriFactu submission.