# `CorvoNfse.Resources.Invoices`
[🔗](https://github.com/corvo-technology/corvo-nfse-elixir/blob/main/lib/corvo_nfse/resources/invoices.ex#L1)

NFS-e invoice lifecycle: create, read, list, iterate, events, downloads and
email.

Resources come straight in the response `data`, so `{:ok, invoice}` is the
invoice map itself (camelCase wire keys, unchanged).

# `list_option`

```elixir
@type list_option() ::
  {:company_id, String.t()}
  | {:status, CorvoNfse.Types.Invoice.status()}
  | {:from, String.t()}
  | {:to, String.t()}
  | {:external_id, String.t()}
  | {:limit, pos_integer()}
  | {:cursor, String.t()}
```

# `option`

```elixir
@type option() ::
  {:idempotency_key, String.t()}
  | {:limit, pos_integer()}
  | {:cursor, String.t()}
```

# `calculate`

```elixir
@spec calculate(CorvoNfse.Client.t(), CorvoNfse.Types.Invoice.create_params()) ::
  {:ok, map()} | {:error, CorvoNfse.Error.t()}
```

Estimates the taxes of an invoice without issuing, storing or charging
anything (`POST /v1/invoices/calculate`).

Takes the same params as `create/3`. A fiscal gap is not an error: the
result has `"status" => "blocked"` with `"blocking"` and `"pendingFields"`.
Money values are decimal strings.

# `create`

```elixir
@spec create(CorvoNfse.Client.t(), CorvoNfse.Types.Invoice.create_params(), [
  {:idempotency_key, String.t()}
]) :: {:ok, map()} | {:error, CorvoNfse.Error.t()}
```

Creates an invoice (`POST /v1/invoices`).

Pass `idempotency_key:` to send the `Idempotency-Key` header. The response
is `202 Accepted`; `{:ok, invoice}` carries the invoice entity.

# `download_url`

```elixir
@spec download_url(
  CorvoNfse.Client.t(),
  String.t(),
  CorvoNfse.Types.Invoice.download_format()
) ::
  {:ok, map()} | {:error, CorvoNfse.Error.t()}
```

Creates a short-lived signed download URL
(`POST /v1/invoices/:id/download-url`).

`format` is `:pdf` or `:xml` (sent as `"pdf"`/`"xml"`).

# `events`

```elixir
@spec events(CorvoNfse.Client.t(), String.t(), [option()]) ::
  {:ok, CorvoNfse.Types.Common.page()} | {:error, CorvoNfse.Error.t()}
```

Lists an invoice's events (`GET /v1/invoices/:id/events`).

# `get`

```elixir
@spec get(CorvoNfse.Client.t(), String.t()) ::
  {:ok, map()} | {:error, CorvoNfse.Error.t()}
```

Reads an invoice (`GET /v1/invoices/:id`).

# `iterate`

```elixir
@spec iterate(CorvoNfse.Client.t(), [list_option()]) ::
  {:ok, Enumerable.t()} | {:error, CorvoNfse.Error.t()}
```

Lazily iterates every invoice across pages.

The first page is fetched eagerly: `{:error, error}` means it failed and
nothing was produced; `{:ok, stream}` yields invoices one by one. A failure
in a later page raises the `%CorvoNfse.Error{}` while consuming the stream.

# `list`

```elixir
@spec list(CorvoNfse.Client.t(), [list_option()]) ::
  {:ok, CorvoNfse.Types.Common.page()} | {:error, CorvoNfse.Error.t()}
```

Lists invoices (`GET /v1/invoices`) with cursor pagination.

Filters use snake_case options (`company_id:`, `external_id:`) and are sent
on the wire as `companyId`, `externalId`, etc.

# `pdf`

```elixir
@spec pdf(CorvoNfse.Client.t(), String.t()) ::
  {:ok, CorvoNfse.Types.Invoice.download()} | {:error, CorvoNfse.Error.t()}
```

Downloads the invoice PDF (`GET /v1/invoices/:id/pdf`) as raw bytes.

# `send_email`

```elixir
@spec send_email(CorvoNfse.Client.t(), String.t(), [{:idempotency_key, String.t()}]) ::
  {:ok, map()} | {:error, CorvoNfse.Error.t()}
```

Triggers the fiscal document email (`POST /v1/invoices/:id/email`).

Pass `idempotency_key:` to send the `Idempotency-Key` header. The response
is `202 Accepted`.

# `xml`

```elixir
@spec xml(CorvoNfse.Client.t(), String.t()) ::
  {:ok, CorvoNfse.Types.Invoice.download()} | {:error, CorvoNfse.Error.t()}
```

Downloads the invoice XML (`GET /v1/invoices/:id/xml`) as raw bytes.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
