---
title: "Export invoices"
method: POST
path: "/v1/companies/{company_id}/invoices/exports"
tags: ["CompanyInvoiceDelivery"]
---

# Export invoices

`POST /v1/companies/{company_id}/invoices/exports`

## Request

- Base URL: `https://app.beel.es/api`
- URL: `https://app.beel.es/api/v1/companies/{company_id}/invoices/exports`
- Auth: HTTP bearer

Produces a spreadsheet with the invoices of this company and returns the file in the
response.

- **Selection:** the invoices named in `invoice_ids`, or, when that is absent, the ones
  matching `filters`. A request with neither is rejected with
  `400 EXPORT_SELECTION_REQUIRED`.
- **Format:** `SUMMARY` writes one row per invoice with aggregated totals, `ITEMS` one
  row per invoice line. To get both, send `formats: [SUMMARY, ITEMS]`: a single file
  with one sheet per format, rather than two requests.
- **Disbursements sheet:** when any exported invoice has `SUPLIDO` lines, the workbook
  gets one more sheet at the end, named `Suplidos`, with one row per source invoice.
  Columns: «Número factura», «Fecha expedición», «Cliente», «NIF cliente», «Factura
  origen», «NIF emisor origen» and «Importe factura origen». The amount is the
  `total_to_pay` of the source invoice; for a manual disbursement with no linked
  invoices it is the line total. When the source invoice is not visible to you, the row
  carries only its number, when known, and the issuer NIF and the amount are empty. The
  sheet is added whatever `formats` you send, and it is not a format: you cannot
  request it or opt out of it.
- **Values:** the status, payment method, tax type and line type columns carry the same
  values the API returns (`ISSUED`, `BANK_TRANSFER`, `IVA`, `SUPLIDO`…). A proforma past
  its validity is exported as `ACTIVE`, not `EXPIRED`.
- **Custom fields:** the `SUMMARY` and `ITEMS` sheets get one extra column per custom
  field `key` carried by at least one exported invoice, after the fixed columns and
  ordered by `key`, so the position of the fixed columns never changes. The header is
  the label saved on the invoices; when the same `key` was saved under different labels
  (the field was renamed between invoices), the label of the most recently created of
  them is used. A cell is empty when its invoice does not carry that field, and every
  line of an invoice repeats the invoice's values in `ITEMS`. The `Suplidos` sheet has
  no custom field columns. With no custom fields on any exported invoice the workbook is
  the same as without them.
- **Limit:** up to 50000 invoices per export. Going over it is rejected with
  `422 EXPORT_LIMIT_EXCEEDED` — narrow the date range or split the selection. The
  export is never silently truncated.

## Request body

- CreateInvoiceExportRequest: An export of the invoices of this company. The format travels in the body, not in the URL, so a new format never adds a route.
  - `format` 'SUMMARY' | 'ITEMS': - **SUMMARY**: one row per invoice with aggregated totals. - **ITEMS**: one row per invoice line. Ignored when `formats` is present.
  - `formats` InvoiceExportFormat[]: Several formats in ONE file: the workbook carries one sheet per format, in the order given (a repeated format yields a single sheet), followed at the end by a disbursements sheet (named `Suplidos`, described in the operation) whenever any exported invoice carries disbursement lines. Takes precedence over `format`; empty or absent, `format` applies.
  - `invoice_ids` UUID[]: Specific invoices to export. When present, `filters` is ignored.
  - `filters` InvoiceExportFilters: Selection criteria used when `invoice_ids` is not supplied. Max 50000 invoices: a wider match is rejected with `422 EXPORT_LIMIT_EXCEEDED`, never truncated.
    - `status` 'SCHEDULED' | 'DRAFT' | 'ISSUED' | 'SENT' | 'PAID' | 'OVERDUE' | 'RECTIFIED' | 'VOIDED' | 'CONVERTED' | 'ACTIVE' | 'EXPIRED': - SCHEDULED: Scheduled invoice to be issued automatically on a future date - DRAFT: Draft invoice not sent yet (modifiable) - ISSUED: Finalized invoice with definitive number but not sent - SENT: Invoice sent to customer - PAID: Invoice paid - OVERDUE: Unpaid invoice in `ISSUED` or `SENT` status, with a total above zero, whose `due_date` is earlier than the current day in Europe/Madrid. A periodic process sets it, so it can lag behind the due date. It changes to `PAID` when the invoice is paid. - RECTIFIED: Partially corrected invoice (one or more PARTIAL corrective invoices) - VOIDED: Cancelled invoice. Reached either through a direct void request or through a TOTAL corrective invoice; `void_cause` tells the two apart. - CONVERTED: Proforma converted into an invoice (terminal; the proforma survives as the record of the accepted quote, linked to the created invoice) - ACTIVE: Active proforma. The single working state of a proforma (non-fiscal document): born numbered (PRO-...) and editable, never reaching the fiscal statuses. It transitions to CONVERTED when turned into an invoice, or to VOIDED when the offer is rejected/withdrawn (POST /v1/invoices/{invoice_id}/void). - EXPIRED: Proforma whose offer validity (`valid_until`) has passed. Derived on read and never stored; the proforma stays convertible and editable.
    - `type` 'STANDARD' | 'CORRECTIVE' | 'SIMPLIFIED' | 'PROFORMA': - STANDARD: Standard invoice - CORRECTIVE: Corrects or cancels a previous invoice - SIMPLIFIED: Simplified invoice (ticket), for a recipient that is not identified. BeeL. requires a STANDARD invoice when the recipient is identified, at any amount: a SIMPLIFIED invoice whose recipient carries an `nif` or `alternative_id` is rejected with `SIMPLIFIED_INVOICE_FORBIDS_IDENTIFIED_RECIPIENT`. The only amount BeeL enforces is a cap of 3,000€ VAT included (`SIMPLIFIED_INVOICE_EXCEEDS_LEGAL_LIMIT`). The general limit of RD 1619/2012 is 400€ (art. 4.1.a); up to 3,000€ applies only to the activities listed in art. 4.2. BeeL does not check which activity the issuer carries out. - PROFORMA: Commercial document (formal quote) with no fiscal validity. Never enters VeriFactu (no QR, no AEAT submission): `verifactu.enabled` is always `false`, whatever the company's regime. Requires full recipient data, like STANDARD. Cannot be corrective nor reference a rectified invoice.
    - `date_from` string, date: Issue date from (inclusive).
    - `date_to` string, date: Issue date to (inclusive).
    - `customer_id` string, uuid: Universally Unique Identifier (UUID v4)
    - `recipient_name` string: Partial match on the recipient name.
    - `recipient_nif` string: Partial match on the recipient tax id.
    - `series_code` string: Exact series code.
    - `custom_fields` object: Filter by the custom fields saved on the invoice, as an object from field `key` to value. It behaves like the `custom_fields` filter of the invoice list: the value is compared with the text stored on the invoice, exactly (case and accents included), and several keys are combined with AND, and with the other filters. Max 20 keys; more answers `422 CUSTOM_FIELD_FILTER_TOO_MANY_KEYS`. A key the company does not have matches no invoice. An empty object filters nothing and does not count as a selection criterion.

## Response `200`

Export generated successfully

## Other responses

- `400`: `EXPORT_SELECTION_REQUIRED` — the request names no invoices: neither a non-empty `invoice_ids` nor a single filter. An export with no criteria is rejected, never answered with the whole account.
- `401`: Missing or invalid authentication. Like every other error, `message`/`detail` is localized according to `Accept-Language` (`es`, `en`, `ca`); defaults to English when the header is missing or asks for none of those.
- `403`: Your account does not own or manage this company, or does not hold the required access over it. A NIF that does not exist answers the same way. That case answers `error.code` `ACTIVE_COMPANY_NOT_ACCESSIBLE`.
- `422`: The body parses but the export cannot be produced as asked. Nothing is exported. - `VALIDATION_ERROR` — a field fails validation; `error.details` maps each offending property to what is wrong with it. - `EXPORT_LIMIT_EXCEEDED` — the selection matches more than 50000 invoices; narrow the date range or split the selection. - `CUSTOM_FIELD_FILTER_TOO_MANY_KEYS` — `filters.custom_fields` has more than 20 keys; narrow the filter to 20 keys or fewer.
- `429`: Rate limit exceeded. `RATE_LIMIT_EXCEEDED` when the request rate of your credential is over its limit; `TOO_MANY_REQUESTS` when an email the operation sends is held back because too many went out to that recipient in a short time. Either way, retry after the `Retry-After` seconds. `QUOTA_EXCEEDED` is the other `429`: the operation would go over a quota of your plan for the current period (issued invoices, for instance). Retrying does not help until the quota resets or the plan changes. `error.details` carries `feature_code`, `current_usage`, `quota_limit` and `reset_date`, and `RateLimit-Reset` the seconds until the reset when it is known.
- `500`: Internal server error
- `default`: Any status code the operation does not list above. Every operation declares it, so a generated client always has a branch to fall into and never loses the cause of a failure it did not anticipate. This is where the transport-level answers land — `405`, `406`, `415` and `429` — together with any status a future version of the API starts returning. All of them carry the same error envelope as the codes listed explicitly, so `error.code` is what tells them apart: switching on the status code alone is not enough. See «Transport-level errors» in the API description for when each one is produced. A `402` carrying `SUBSCRIPTION_REQUIRED` lands here when the account has no active subscription. `error.details` says why and what to do: `current_status` (absent if it never had one), `required_permission` and `action`. A `503` carrying `SERVICE_UNAVAILABLE` lands here too, with a `Retry-After` header: a dependency of BeeL itself (the database, the email provider) was momentarily unavailable and nothing was done. Retry after those seconds. A `502` carrying `EXTERNAL_SERVICE_ERROR` also lands here: an outbound integration the operation depends on failed or did not answer in time. It is a transient condition — retry with the same `Idempotency-Key` where the operation accepts one. One exception to the envelope: a failure of the network edge that never reaches the application (`502`, `503`, `504`, `524`) is generated by Cloudflare and its body is not BeeL's — it may not even be JSON. Treat those as "no answer", and retry.

---

[API](https://skmtc.dev/beel/apis/beel-public-api.md) · [All operations](https://skmtc.dev/beel/apis/beel-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/beel/apis/beel-public-api/revisions/ffbc0ae31f79?raw)
