> ## 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.

# Get Started with facturas: Issue Your First Invoice

> Install facturas, set your ARCA credentials as environment variables, and issue your first electronic invoice in under five minutes.

This guide takes you from a blank project to an authorized electronic invoice against ARCA's homologación (test) environment. You'll install the package, point it at your credentials, issue a Factura C, and learn how to handle every possible outcome. Before you start, make sure you have a valid CUIT, a certificate registered in ARCA's WSASS portal, and a sales point enabled for web services — if you haven't done that yet, follow the [ARCA Setup](arca-setup) guide first and come back here.

<Steps>
  <Step title="Install facturas">
    Add the `facturas` package to your project. Node.js 20 or later is required, and the package is ESM-only.

    <CodeGroup>
      ```bash pnpm theme={null}
      pnpm add facturas
      ```

      ```bash npm theme={null}
      npm install facturas
      ```

      ```bash yarn theme={null}
      yarn add facturas
      ```
    </CodeGroup>

    If your project is not already ESM, add `"type": "module"` to your `package.json`.
  </Step>

  <Step title="Set environment variables">
    The client reads four required variables. Set them in your shell, `.env` file, or deployment platform before running your code.

    ```bash theme={null}
    export ARCA_TAX_ID=20123456786          # Your 11-digit CUIT
    export ARCA_ENVIRONMENT=test            # "test" for homologación, "production" for live
    export ARCA_CERTIFICATE_PEM="$(cat arca-test.crt)"   # Full PEM certificate
    export ARCA_PRIVATE_KEY_PEM="$(cat arca-test.key)"   # Full PEM private key
    ```

    | Variable               | Required | Notes                                              |
    | ---------------------- | -------- | -------------------------------------------------- |
    | `ARCA_TAX_ID`          | Yes      | 11-digit CUIT, with or without hyphens             |
    | `ARCA_ENVIRONMENT`     | Yes      | `test` (homologación) or `production` — no default |
    | `ARCA_CERTIFICATE_PEM` | Yes      | Full PEM block including `BEGIN`/`END` lines       |
    | `ARCA_PRIVATE_KEY_PEM` | Yes      | Full PEM block including `BEGIN`/`END` lines       |

    <Note>
      Never commit PEM values to your repository. Use your platform's secret management (Vercel environment variables, AWS Secrets Manager, etc.) to inject them at runtime. See the [ARCA Setup](arca-setup) guide for how to generate and register these credentials.
    </Note>

    Before writing any application code, confirm that every layer is working:

    ```bash theme={null}
    npx facturas check
    ```

    `check` tests your configuration, certificate, WSAA authentication, WSFE connectivity, and sales points in that order, and names the exact layer that fails if something is wrong — without writing anything to ARCA.
  </Step>

  <Step title="Issue your first invoice">
    Create a client and call `arca.issue()`. The client reads the environment variables you set above — no constructor arguments required for a basic setup.

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

    const arca = createArcaClient();

    const factura = await arca.issue({
      issuer: "monotributo",      // Your fiscal condition
      salesPoint: 3,              // Your enabled sales point number
      to: { condition: "consumidor_final" },
      items: [{ amount: 150_000 }], // ARS 1,500.00 — amounts are integer centavos (minor units)
    });
    ```

    <Tip>
      Amounts are always **integer centavos** (minor units). `150_000` represents ARS 1,500.00 — multiply your peso amount by 100. Use the numeric separator `_` freely for readability.
    </Tip>

    For a **responsable inscripto** issuer, include the VAT rate on each item:

    ```ts theme={null}
    const factura = await arca.issue({
      issuer: "responsable_inscripto",
      salesPoint: 3,
      to: { condition: "responsable_inscripto", taxId: "20987654321" },
      items: [{ gross: 12_100, vat: 21 }], // ARS 121.00 gross, 21% VAT
    });
    ```

    Before calling `issue()`, you can inspect the derived invoice type and amounts with `preview()`. It runs synchronously and makes no network calls:

    ```ts theme={null}
    const preview = arca.preview({
      issuer: "monotributo",
      salesPoint: 3,
      to: { condition: "consumidor_final" },
      items: [{ amount: 150_000 }],
    });

    console.log(preview.voucherType);          // e.g. "Factura C"
    console.log(preview.amounts.sentTotal);    // verify this matches your sale total
    ```

    Compare `preview.amounts.sentTotal` against the total on your sale record before calling `issue()`.
  </Step>

  <Step title="Handle every outcome">
    `arca.issue()` returns one of four typed outcomes. Always handle all four — don't assume success.

    | Outcome         | Meaning                                               | What to do                                                                                                                                                     |
    | --------------- | ----------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `authorized`    | ARCA issued a CAE.                                    | Save `factura.voucher` and its CAE immediately. If `recoveredByMatch: true`, the stored input matched a prior attempt — consistency is proven, not authorship. |
    | `rejected`      | ARCA refused the invoice.                             | Inspect `factura.issues` for ARCA's error codes and correct the input before retrying. A key stays bound to its input even after rejection.                    |
    | `indeterminate` | ARCA's response was ambiguous.                        | Preserve the voucher number and evidence. Reconcile manually or retry with the identical input and its existing idempotency key.                               |
    | `conflict`      | Another voucher already occupies the reserved number. | Stop the flow and investigate. Do not retry without understanding what holds that number.                                                                      |

    ```ts theme={null}
    switch (factura.kind) {
      case "authorized":
        // Save factura.voucher.cae and factura.voucher to your database
        console.log("CAE:", factura.voucher.cae);
        break;

      case "rejected":
        // Log ARCA's issues and surface them to your team
        console.error("Rejected:", factura.issues);
        break;

      case "indeterminate":
        // Preserve evidence; do not discard the voucher number
        console.warn("Indeterminate:", factura.evidence);
        break;

      case "conflict":
        // A different document occupies this number — stop and investigate
        console.error("Conflict at number:", factura.number);
        break;
    }
    ```

    <Warning>
      Do not discard an `indeterminate` or `conflict` result. The voucher number has been reserved with ARCA regardless of whether the authorization response was clear. Discarding it can create a gap in your sequence that ARCA will flag.
    </Warning>
  </Step>
</Steps>

## Next steps: safe retries with idempotency

The steps above are enough to issue invoices, but in production you should add a `store` and an `idempotencyKey`. Without them, a process crash between number reservation and authorization can cause a duplicate invoice on retry.

```ts theme={null}
import { createArcaClient, createPostgresStore } from "facturas";
import { sql } from "@vercel/postgres";

const arca = createArcaClient({
  store: createPostgresStore({ query: (text, params) => sql.query(text, params) }),
});

// Pass your sale's stable ID as the idempotency key.
// On retry, the SDK looks up the reserved number instead of issuing again.
const factura = await arca.issue(input, { idempotencyKey: venta.id });
```

Adapters are available for **Postgres**, **Redis**, **file**, and **memory** (memory is for tests and does not survive process restarts). Use 1–255 characters for the key, without personal data like CUIT or DNI, and never generate a new key per attempt.

## Try it with the CLI

To test the full circuit before writing code, the CLI can issue a real ARS 1.00 invoice in homologación and print the exact `arca.issue()` call it made:

```bash theme={null}
npx facturas issue --sales-point 3 --issuer monotributo
```

This only works in `test` environment and is a real homologación document.
