# 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](https://app.beel.es/signup) and create a key with the `beel_sk_test_` prefix — see [API keys](/auth/api-keys). No card is needed.
- **Cost.** Free. Only production is billed, and sandbox invoices never count towards a plan's invoices — see [Pricing](/pricing#what-counts-as-an-invoice).
- **Time limit.** None: the sandbox does not expire.
- **Limits.** The same [rate limits](/guides/rate-limits) as production, and a lower email quota — in sandbox, email only goes to your own address ([Sending email](/guides/sending-email#sandbox-only-sends-to-your-own-address)). BeeL.'s [Terms](https://beel.es/terminos) 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. 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](/verifactu/enabling-verifactu).

## What is different from Live

| | Sandbox | Live |
|---|---|---|
| VeriFactu | **Always on.** Every invoice of the NIF is submitted | On only once you [enable it](/verifactu/enabling-verifactu) |
| Turning it off | Not possible — `enabled: false` returns `422` [`VERIFACTU_ALWAYS_ON_IN_SANDBOX`](/errors/VERIFACTU_ALWAYS_ON_IN_SANDBOX) | `PUT … { "enabled": false }` |
| Representation | **Not needed** — there is nothing to authorise | Must be signed before enabling |
| NIF registration | Done for you, asynchronously | Done in the enabling call |
| Where submissions go | AEAT's test environment | AEAT |
| QR code | Points to AEAT's test validation service | Points to AEAT's validation service |

## 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`](/errors/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](/multi-nif/companies#switching-a-nif-on-in-test-or-live) — 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](/stripe/verifactu-submission).

> **Rules that apply here:** [LIF-003 · Test in the sandbox, never with real invoices](/rules/lifecycle#lif-003)

## Related

<Related>

- [Enabling VeriFactu for a NIF](/verifactu/enabling-verifactu) — the Live path
- [Submission states](/verifactu/submission-states) — the same states in both environments
- [QR code and the invoice PDF](/verifactu/qr-and-pdf) — when the QR exists

</Related>

---

Full OpenAPI spec: https://docs.beel.es/api/openapi