Test mode & sandbox
Build your integration safely with fact_test_ keys — isolated sandbox data and AEAT, email and webhooks switched off.
Every Factuarea API key belongs to one of two environments, told apart by its prefix:
| Prefix | Environment | Operates on | External effects |
|---|---|---|---|
fact_live_ | live (production) | Your real company | Real: legal fiscal numbering, VeriFactu → AEAT, FACe submissions, emails to clients, outbound webhooks |
fact_test_ | test (sandbox) | An isolated sandbox company | Switched off (see below) |
The prefix is the source of truth for the environment: a fact_test_
key always operates in test mode and a fact_live_ key always in live. No
request parameter changes the environment — it is determined entirely by
the key you authenticate with.
Always build and test your integration with a fact_test_ key first.
Once your flow works end-to-end, switch the prefix to fact_live_ to go
to production. The API surface is identical in both environments.
Getting a test key
Test keys are created from the developer dashboard exactly like live keys, selecting the Test environment (app.factuarea.com/settings/developers/api-keys). The generated secret looks like:
fact_test_<24 alphanumeric characters>Example:
fact_test_3pXnR2VbY7TcA9eFmN5z8KqWSame format and entropy as a live key (24 base62 characters), same scopes, same rate-limit tier. The only difference is the prefix and what it points to. As with live keys, the secret is shown only once at creation — if you lose it you must rotate.
Using a test key
Send it on every request just like a live key, via Authorization: Bearer
or X-API-Key:
curl https://api.factuarea.com/v1/clients \
-H "Authorization: Bearer fact_test_3pXnR2VbY7TcA9eFmN5z8KqW"The same endpoints and operations available in live are available in test — nothing is removed or stubbed.
Data isolation: the sandbox company
A fact_test_ key operates on a dedicated sandbox company — a technical
"twin" of your real company, provisioned automatically the first time you
use test mode, that inherits your real company's plan so feature-gating is
faithful. Thanks to multi-tenant isolation by company:
- Resources created with a
fact_test_key are not visible to afact_live_key, and vice versa. - Test fiscal numbering uses the sandbox's own series and never consumes or alters the correlative numbering of your production series.
This is structural isolation, not a filter: test and live data live in separate companies, so there is no way for them to mix.
What is switched off in test
When you operate with a fact_test_ key (sandbox environment), effects that
reach the outside world are disabled so you can exercise your
integration without real-world consequences:
| Effect | In live | In test |
|---|---|---|
| VeriFactu | The Alta record is created and transmitted to the AEAT. | The Alta record is created locally, but never transmitted to the AEAT. |
| Document emails are delivered to real recipients. | Document emails are not delivered to real recipients. | |
| Webhooks | Subscribed events are delivered to your external HTTP endpoints. | Events are recorded with livemode: false (queryable via GET /v1/events) but not delivered to your endpoints. |
| FACe (FacturaE) | Submissions are presented to the real FACe web service. | The whole flow is simulated — no SOAP call leaves Factuarea and the registry number is synthetic (FACE-SANDBOX-*). See FACe invoicing. |
Everything else behaves identically: validation, totals, document state machines, idempotency, pagination, rate limits and error envelopes are the same as in production.
Because webhooks are not delivered in test, you cannot exercise your
webhook receiver against sandbox data. Test your endpoint's signature
verification with the dedicated POST /v1/webhook_endpoints/{id}/ping
(which is delivered) or against a live key on a controlled event.
With the official SDKs
The TypeScript and PHP SDKs follow the same rule: the key
prefix selects the environment — there is no flag. Build against a
fact_test_ key, then swap the env var to fact_live_ to go to production.
No code changes.
import { Factuarea } from "@factuarea/sdk";
const sandbox = new Factuarea({ apiKey: "fact_test_…" });
sandbox.environment; // "test"
const prod = new Factuarea({ apiKey: "fact_live_…" });
prod.environment; // "live"The SDK exposes the resolved environment on .environment, derived from
the prefix — handy for guards and logging.
use Factuarea\Sdk\Custom\FactuareaClient;
$sandbox = FactuareaClient::create('fact_test_…'); // sandbox
$prod = FactuareaClient::create('fact_live_…'); // productionWebhooks are still not delivered in test even via the SDK. To exercise
your receiver's SDK verifier in sandbox,
use POST /v1/webhook_endpoints/{id}/ping, which is delivered.
Switching environment in the app
Beyond API keys, the Factuarea web app lets you toggle between live and test at any time from the top bar. Switching to test:
- Re-issues your session without re-login, pointing it at the sandbox company (provisioning it if it doesn't exist yet). The previous token is invalidated.
- Shows a persistent "MODO TEST" banner across the whole interface so the active context is always obvious.
- Re-hydrates the client state so listings reflect sandbox data and never show cached production data.
Switching back to live re-issues the session against your real company. The sandbox is never shown as a real company in the company selector — it exists only to back the test environment.
From test to production
When your integration works against fact_test_:
- Create a
fact_live_key in the dashboard (same scopes you validated in test). - Swap the key your client uses (environment variable / secret manager).
- No code changes are needed — the request shape is identical.
From that point, real effects (fiscal numbering, VeriFactu → AEAT, emails, webhooks) are active again.
Authentication
API keys with fact_live_ / fact_test_ prefixes, fine-grained scopes, grace-period rotation and IP allowlist.
Overview
Official TypeScript and PHP SDKs for the Factuarea API — install @factuarea/sdk or factuarea/factuarea-php and get retries, idempotency, cursor pagination, typed errors and webhook verification out of the box.