> ## Documentation Index
> Fetch the complete documentation index at: https://facturas-sdk.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# facturas Public API Reference

> Complete reference for the facturas public API: createArcaClient, issue, issueCreditNote, preview, recover, and store constructors. Covered by semver.

The `facturas` package exposes a small, stable public API covered by semantic versioning. Every method, type, and store constructor documented on this page will not change in a breaking way without a version bump. You can import from the package root `facturas` or from its named sub-paths — all of them are listed at the end of this page.

<Warning>
  **facturas is pre-1.0.** Minor version bumps may include breaking changes. Pin an exact version in your `package.json` — for example `"facturas": "0.11.0"` — and review the changelog before upgrading.
</Warning>

***

## `createArcaClient(options?)`

The main factory function. Call it once at startup and reuse the returned `ArcaClient` instance throughout your application.

```ts twoslash theme={null}
import { createArcaClient } from "facturas";

const arca = createArcaClient({
  taxId: "20123456786",
  certificatePem: process.env.ARCA_CERTIFICATE_PEM!,
  privateKeyPem: process.env.ARCA_PRIVATE_KEY_PEM!,
  environment: "test",
});
```

All options fall back to the corresponding environment variable when omitted. Explicit values always win over environment variables. If a required field is missing from both the options object and the environment, `createArcaClient` throws `ArcaConfigurationError` immediately.

### Options

<ParamField body="taxId" type="string" required>
  Your 11-digit CUIT (tax ID). Falls back to the `ARCA_TAX_ID` environment variable.
</ParamField>

<ParamField body="certificatePem" type="string" required>
  PEM-encoded ARCA/AFIP certificate issued for your CUIT. Falls back to `ARCA_CERTIFICATE_PEM`. Treat this value as a secret.
</ParamField>

<ParamField body="privateKeyPem" type="string" required>
  PEM-encoded private key matching the certificate above. Falls back to `ARCA_PRIVATE_KEY_PEM`. Treat this value as a secret.
</ParamField>

<ParamField body="environment" type="&#x22;test&#x22; | &#x22;production&#x22;" required>
  Target ARCA environment. Falls back to `ARCA_ENVIRONMENT`. There is no default — the client throws if this is absent from both sources.
</ParamField>

<ParamField body="timeout" type="number" default="30000">
  HTTP request timeout in milliseconds.
</ParamField>

<ParamField body="retries" type="number" default="0">
  Number of additional transport-layer retry attempts. Retries apply only to `ArcaTransportError` (connection failures, timeouts, non-XML HTTP error responses). SOAP faults and service-level errors are never retried automatically.
</ParamField>

<ParamField body="retryDelay" type="number" default="500">
  Milliseconds to wait between transport retries.
</ParamField>

<ParamField body="logger" type="ArcaLoggerConfig">
  Optional structured logger configuration. Pass `{ level: "debug" }` to enable SOAP traces, WSAA login origin, and retry logs. Pass `{ disabled: true }` to suppress all SDK output. Provide a custom sink via `{ level, log(level, message, ...args) { … } }`. The default minimum level is `warn`. You can also set `ARCA_LOG_LEVEL` in the environment without touching code.
</ParamField>

<ParamField body="store" type="ArcaStore">
  A unified durable store for WSAA session tickets **and** invoice/credit-note idempotency reservations. Providing a store enables durability across process restarts and serverless cold starts. See [Store Constructors](#store-constructors) below.
</ParamField>

<ParamField body="wsaaSessionStore" type="ArcaWsaaSessionStore">
  An optional separate store used only for WSAA login tickets. Takes priority over `store` for ticket management. Useful when you already have a shared cache and only want to persist auth tokens, not issuance reservations.
</ParamField>

***

## `ArcaClient` Methods

### `issue(input, options?)`

Derives the ARCA request, reserves the next voucher number, sends the authorization, and returns the fiscal outcome. On an indeterminate result (timeout, connection loss, inconclusive response), `issue` automatically looks up the voucher at ARCA before returning — so you never need to check manually on a subsequent call.

```ts twoslash theme={null}
import { createArcaClient } from "facturas";
const arca = createArcaClient({ taxId: "20123456786", certificatePem: "", privateKeyPem: "", environment: "test" });
// ---cut---
const outcome = await arca.issue({
  salesPoint: 1,
  receiverName: "Juan Pérez",
  receiverVatCondition: "consumidor_final",
  lines: [{ description: "Consultoría", quantity: 1, unitPrice: 10000 }],
});

if (outcome.kind === "authorized") {
  console.log(outcome.voucher.cae, outcome.voucher.caeExpiry);
}
```

**Returns:** `Promise<IssueOutcome>`

<ParamField body="input" type="IssueInput" required>
  High-level invoice descriptor. See the [Invoices guide](/concepts/invoices) for the full field list.
</ParamField>

<ParamField body="options.service" type="&#x22;wsfe&#x22; | &#x22;wsmtxca&#x22;" default="&#x22;wsfe&#x22;">
  Target service. Pass `"wsmtxca"` to issue with full line-item detail via WSMTXCA.
</ParamField>

<ParamField body="options.number" type="number">
  An externally reserved voucher number. When supplied, `issue` skips the automatic `getNextVoucherNumber` call and uses this number instead.
</ParamField>

<ParamField body="options.idempotencyKey" type="string">
  An application-level key that ties the operation to your store reservation. Replaying the same key with the same input recovers the previous result; replaying with a different input throws `ARCA_INPUT_IDEMPOTENCY_MISMATCH`.
</ParamField>

<ParamField body="options.representedTaxId" type="string | number">
  CUIT of the taxpayer on whose behalf you are issuing (for multi-tenant integrations).
</ParamField>

<ParamField body="options.forceRefresh" type="boolean">
  Discard the cached WSAA ticket and obtain a fresh one before this call.
</ParamField>

<ParamField body="options.include.raw" type="boolean">
  Include the raw ARCA SOAP response on the returned outcome.
</ParamField>

<ParamField body="options.include.exactInput" type="boolean">
  Include the exact `WsfeVoucherInput` or `WsmtxcaIssueRequest` that was sent to ARCA on the returned outcome under `sent`.
</ParamField>

***

### `preview(input, options?)`

Derives the ARCA request object that `issue` would send, without making any network calls or reserving a number. Use this to inspect the fiscal amounts, derived voucher type, and service-level payload before committing.

```ts twoslash theme={null}
import { createArcaClient } from "facturas";
const arca = createArcaClient({ taxId: "20123456786", certificatePem: "", privateKeyPem: "", environment: "test" });
// ---cut---
const preview = await arca.preview({
  salesPoint: 1,
  receiverName: "Empresa SRL",
  receiverVatCondition: "responsable_inscripto",
  receiverTaxId: "30999888777",
  lines: [{ description: "Software", quantity: 1, unitPrice: 50000 }],
});

console.log(preview.voucherClass); // "A"
console.log(preview.amounts.total);
```

**Returns:** `IssuePreview`

***

### `recover(key)`

Looks up a previously stored idempotency reservation by its key. Returns the stored record if it exists, or `undefined` if no reservation was found under that key.

```ts twoslash theme={null}
import { createArcaClient } from "facturas";
const arca = createArcaClient({ taxId: "20123456786", certificatePem: "", privateKeyPem: "", environment: "test" });
// ---cut---
const reservation = await arca.recover("invoice-order-42");
if (reservation) {
  console.log(reservation.coordinates, reservation.operation);
}
```

**Returns:** `Promise<…reservation | undefined>`

***

### `issueCreditNote(input, options?)`

Issues a credit note against a previously authorized voucher. Accepts the same options as `issue`.

```ts twoslash theme={null}
import { createArcaClient } from "facturas";
const arca = createArcaClient({ taxId: "20123456786", certificatePem: "", privateKeyPem: "", environment: "test" });
// ---cut---
const outcome = await arca.issueCreditNote({
  salesPoint: 1,
  associatedVoucher: {
    salesPoint: 1,
    voucherType: 6,
    number: 42,
    date: "2026-09-01",
    cuit: "20123456786",
  },
  lines: [{ description: "Devolución parcial", quantity: 1, unitPrice: 5000 }],
});
```

**Returns:** `Promise<IssueOutcome>`

***

### `issueDebitNote(input, options?)`

Issues a debit note against a previously authorized voucher. Accepts the same options as `issue`.

**Returns:** `Promise<IssueOutcome>`

***

### `previewCreditNote(input, options?)`

Derives the ARCA request a credit note issuance would send, with no network calls.

**Returns:** `IssuePreview`

***

### `previewDebitNote(input, options?)`

Derives the ARCA request a debit note issuance would send, with no network calls.

**Returns:** `IssuePreview`

***

### `arca.wsfe`

The low-level WSFE service handle. Exposes raw ARCA methods including `authorize`, `getNextVoucherNumber`, `getLastAuthorizedVoucher`, `lookupVoucher`, and runtime catalog methods. See [Exact Layer](/reference/exact-layer) for the full surface.

***

### `arca.wsmtxca`

The low-level WSMTXCA service handle. Same pattern as `wsfe`, adding full line-item encoding. See [Exact Layer](/reference/exact-layer) for details.

***

### `arca.padron`

The Padrón service handle. Use it to look up taxpayer details or resolve a CUIT from a document number.

```ts twoslash theme={null}
import { createArcaClient } from "facturas";
const arca = createArcaClient({ taxId: "20123456786", certificatePem: "", privateKeyPem: "", environment: "test" });
// ---cut---
const taxpayer = await arca.padron.getTaxpayerDetails("20123456786");
if (taxpayer) {
  console.log(taxpayer.name, taxpayer.personType);
}

const result = await arca.padron.getTaxIdByDocument("12345678");
if (result) {
  console.log(result.taxIds);
}
```

<Note>
  Padrón "not found" detection relies on SOAP fault message text from ARCA, which is less reliable than the code-based flows used by WSFE. Handle `null` returns defensively.
</Note>

***

## Store Constructors

All four store constructors are part of the public semver contract. Pass the result of any of them as the `store` option to `createArcaClient`. A single store covers both WSAA session tickets and issuance idempotency reservations.

<Warning>
  Store reservation records contain fiscal and customer data. Restrict access to the underlying storage and protect backups accordingly. You cannot delete, expire, or overwrite reservation records — doing so can cause a retry to issue a duplicate invoice.
</Warning>

### `createPostgresStore(options)`

Uses your application's existing Postgres client. Compatible with Neon, Supabase Postgres, Vercel Postgres, `pg`, and `postgres`.

```ts twoslash theme={null}
import { createPostgresStore, createArcaClient } from "facturas";
// ---cut---
// Create the table once:
// CREATE TABLE arca_store (
//   key text PRIMARY KEY,
//   value text NOT NULL,
//   updated_at timestamptz NOT NULL DEFAULT now()
// );

const store = createPostgresStore({
  query: (text, params) => pool.query(text, params),
  table: "arca_store", // optional, this is the default
});
```

<ParamField body="options.query" type="(text: string, params: unknown[]) => Promise<…>" required>
  A parameterized query function. Results can be an array of rows or an object `{ rows }`. For the `postgres` package, adapt with `sql.unsafe(text, params)`.
</ParamField>

<ParamField body="options.table" type="string" default="&#x22;arca_store&#x22;">
  Name of the table to use. Must be a simple SQL identifier (no schema prefix or quoting).
</ParamField>

***

### `createRedisStore(redis, options?)`

Wraps an ioredis or Upstash Redis client.

```ts twoslash theme={null}
import { createRedisStore, createArcaClient } from "facturas";
declare const redis: any;
// ---cut---
const store = createRedisStore(redis);
// For Upstash:
// const store = createRedisStore(redis, { flavor: "upstash" });
```

<Note>
  Use a durable Redis instance with no eviction on reservation keys. Neither adapter sets a TTL on reservation records.
</Note>

***

### `createFileStore(directory)`

Persists keys as individual files under `directory`. Suitable for single-server deployments with a private, durable volume.

```ts twoslash theme={null}
import { createFileStore } from "facturas";
// ---cut---
const store = createFileStore("/private/durable/arca");
```

Files are created with mode `0600`; new directories are created with `0700`. Keys are hashed to filenames. No process-level locking is provided.

***

### `createMemoryStore()`

An in-process store for tests and examples. Does not survive process restarts and cannot coordinate across workers.

```ts twoslash theme={null}
import { createMemoryStore } from "facturas";
// ---cut---
const store = createMemoryStore();
```

***

## `createPadronService(options)`

Creates a Padrón service instance wired with the provided authentication and SOAP transport. In most applications you access Padrón directly via `arca.padron`, which is created automatically by `createArcaClient`. The standalone constructor is exported from `facturas/padron` for integration scenarios where you assemble the SDK's internal modules yourself.

**Returns:** `PadronService` with `getTaxpayerDetails(taxId)` and `getTaxIdByDocument(documentNumber)`.

```ts twoslash theme={null}
import { createArcaClient } from "facturas";
// ---cut---
// Standard usage: access padron through the client instance.
const arca = createArcaClient({
  taxId: "20123456786",
  certificatePem: process.env.ARCA_CERTIFICATE_PEM!,
  privateKeyPem: process.env.ARCA_PRIVATE_KEY_PEM!,
  environment: "test",
});

const taxpayer = await arca.padron.getTaxpayerDetails("20123456786");
if (taxpayer) {
  console.log(taxpayer.name, taxpayer.personType);
}
```

***

## Error Classes

All SDK errors extend `ArcaError` and carry a stable `code` string. Import error classes from either `facturas` or `facturas/errors`.

```ts twoslash theme={null}
import {
  ArcaError,
  ArcaConfigurationError,
  ArcaInputError,
  ArcaAuthenticationError,
  ArcaTransportError,
  ArcaSoapFaultError,
  ArcaServiceError,
  isArcaAuthenticationError,
  toArcaSafeErrorMetadata,
} from "facturas/errors";
```

<Accordion title="Error class summary">
  | Class                     | When thrown                                                                                                       |
  | ------------------------- | ----------------------------------------------------------------------------------------------------------------- |
  | `ArcaConfigurationError`  | Invalid client configuration (missing credentials, bad environment, store failure)                                |
  | `ArcaInputError`          | Invalid caller input — for example, a malformed date or a negative amount                                         |
  | `ArcaAuthenticationError` | Explicit authentication rejection from ARCA; carries a typed `reason`, service, operation, and safe provider code |
  | `ArcaTransportError`      | HTTP or network failure; carries an optional `statusCode`                                                         |
  | `ArcaSoapFaultError`      | A SOAP fault returned by ARCA; carries `faultCode`                                                                |
  | `ArcaServiceError`        | Business-level service rejection (e.g., WSFE error codes); carries `serviceCode`                                  |
</Accordion>

Use `isArcaAuthenticationError(error)` as a type-narrowing predicate when you cannot use `instanceof` (for example, across module boundaries). Use `toArcaSafeErrorMetadata(error)` to extract a structured, loggable error summary that never includes raw credentials or request bodies.

```ts twoslash theme={null}
import { ArcaAuthenticationError, ArcaServiceError, ArcaSoapFaultError, ArcaTransportError } from "facturas/errors";
import { createArcaClient } from "facturas";
const arca = createArcaClient({ taxId: "20123456786", certificatePem: "", privateKeyPem: "", environment: "test" });
// ---cut---
try {
  await arca.wsfe.getNextVoucherNumber({ salesPoint: 1, voucherType: 6 });
} catch (error) {
  if (error instanceof ArcaAuthenticationError) {
    console.error(error.reason, error.service, error.operation, error.providerCode);
  } else if (error instanceof ArcaServiceError) {
    console.error(error.serviceCode, error.message);
  } else if (error instanceof ArcaSoapFaultError) {
    console.error(error.faultCode, error.message);
  } else if (error instanceof ArcaTransportError) {
    console.error(error.statusCode, error.message);
  }
  throw error;
}
```

***

## Package Exports

The `facturas` package exposes the following named sub-paths. All of them are stable and covered by semver.

<CardGroup cols={2}>
  <Card title="facturas" icon="cube">
    Main entry point. `createArcaClient`, builder functions, error classes, store constructors, and all public types.
  </Card>

  <Card title="facturas/errors" icon="triangle-exclamation">
    All error classes and predicate helpers in isolation. Useful for libraries that handle errors without importing the full client.
  </Card>

  <Card title="facturas/constants" icon="list">
    ARCA reference data: voucher type codes, VAT rates, document types, currencies, and receiver conditions. See [Constants](/reference/constants).
  </Card>

  <Card title="facturas/types" icon="file-code">
    All public TypeScript types without runtime code.
  </Card>

  <Card title="facturas/wsfe" icon="bolt">
    `createWsfeService` and all WSFE-specific types. See [Exact Layer](/reference/exact-layer).
  </Card>

  <Card title="facturas/wsmtxca" icon="bolt">
    `createWsmtxcaService` and all WSMTXCA-specific types. See [Exact Layer](/reference/exact-layer).
  </Card>

  <Card title="facturas/padron" icon="address-card">
    `createPadronService` and Padrón result types.
  </Card>
</CardGroup>

```ts twoslash theme={null}
import { createWsfeService } from "facturas/wsfe";
import { ARCA_VOUCHER_TYPES } from "facturas/constants";
import { ArcaServiceError } from "facturas/errors";
```

<Note>
  Internal SOAP, HTTP, and WSAA modules are not part of the semver contract and should not be imported directly. Stick to the sub-paths listed above.
</Note>
