store serves two purposes in the facturas SDK: it records immutable voucher reservations so retries never produce duplicate invoices, and it caches WSAA login tickets so multiple workers share the same authenticated session. The SDK ships adapters for Postgres, Redis, file storage, and in-memory — or you can implement the ArcaStore interface directly against any backing store you already use.
How stores are used
Voucher idempotency
Before authorizing a voucher, the SDK writes an immutable reservation keyed by your
idempotencyKey. On a retry with the same key, the SDK looks up the reservation, confirms the input matches, and queries ARCA for the outcome — without issuing a second CAE request.WSAA session cache
A configured
store caches WSAA login tickets so that a warm process reuses a valid ticket obtained by another worker. Providing an explicit wsaaSessionStore targets ticket caching only and takes priority over the unified store.Postgres
createPostgresStore wraps any client that exposes a parameterized query function. Neon, Supabase Postgres, Vercel Postgres, pg, and postgres all work — results can be a row array or a { rows } object.
Provision the table once before first use:
table option if you need to use a different table name. The value must be a simple SQL identifier ([a-zA-Z_][a-zA-Z0-9_]*):
INSERT ... ON CONFLICT DO NOTHING RETURNING key. The adapter never creates the table or acquires a database-level lock — provisioning is your responsibility.
Redis
createRedisStore accepts an ioredis or Upstash client. The SDK auto-detects the flavor by checking for a call method (ioredis) or falling back to Upstash. Pass { flavor: "upstash" } to override detection explicitly.
SET key value NX (ioredis) or set(key, value, { nx: true }) (Upstash) for atomic reservation writes. No TTL is applied.
File store
createFileStore persists records to a local directory. Keys are hashed to filenames; writes use an exclusive-create + atomic-rename strategy to avoid partial writes. Files are created with mode 0600 and new directories with 0700.
Memory store
createMemoryStore keeps records in a plain JavaScript Map for the lifetime of the process. It serializes WSAA ticket refreshes within the shared object, but records do not survive a restart.
Custom store
Implement theArcaStore interface to connect any backing store:
add method must be atomically exclusive — it must return false without modifying the stored value if the key already exists. This is the operation that makes voucher idempotency safe under concurrent retries.
Store key structure and record lifetime
Store keys follow these patterns:- WSAA tickets:
arca:v1:wsaa:{environment}:{service}:{fingerprint} - Voucher reservations:
arca:v1:attempt:{environment}:{taxId}:{idempotencyKey}
v: 1 records are plain WSFE reservations readable by any SDK version from 0.9 onward. v: 2 records are WSMTXCA or itemized reservations — they always identify their provider, and SDK version 0.10 cannot replay them, which prevents a rollback from re-sending a WSMTXCA voucher through WSFE by accident. Preserve both versions.
Repeating an idempotency key with a different input, operation, provider, or explicit voucher number is an idempotency mismatch and throws ARCA_INPUT_IDEMPOTENCY_MISMATCH.
Using one store for both purposes
You can pass the same store instance tostore (for voucher idempotency) and rely on it automatically for WSAA ticket caching. The SDK namespaces all keys, so a single Postgres table or Redis database handles both safely:
wsaaSessionStore to override ticket caching while keeping the unified store for voucher idempotency.