> ## Documentation Index
> Fetch the complete documentation index at: https://www.finseed.es/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Download an invoice PDF

> Returns a signed `download_url` you can hand straight to a browser to download the invoice PDF, so your API key never reaches the client. The link is a same-origin URL on the API host and stays valid for 24 hours, long enough to embed in a page; request a fresh one once it expires. This endpoint authenticates your integration, not your end users: it can reach every invoice in the key's environment, so check in your own app that the signed-in user may see this invoice before calling it.

Every invoice has a PDF. This endpoint returns a signed `download_url` to it. The link stays valid for 24 hours, shown in `expires_at` — long enough to embed in a page your own client opens later. Request a fresh one once it expires rather than storing it indefinitely.

There are two common ways to use it:

* **Download invoices to your own systems.** Page through the [list of invoices](/docs/api-reference/pagination), then call this endpoint for each one and save the PDF on your side. This runs server to server, behind your API key.
* **Let your users download an invoice.** When a user clicks "download" in your app, call this endpoint from your backend and redirect the browser to `download_url`. Your API key stays on your server, and the browser only ever sees the short-lived link.

This endpoint authenticates your integration, not your end users: your API key can reach every invoice in its environment. Before you return an invoice to a signed-in user, check in your own application that the invoice belongs to them.


## OpenAPI

````yaml GET /v1/invoices/{id}/download
openapi: 3.1.0
info:
  title: Finseed API
  version: 1.0.0
  description: >-
    REST API for programmatic Verifactu invoicing. Every request is sent over
    HTTPS and authenticated with an API key passed as a bearer token. Each key
    is scoped to a single environment (test or live). Payloads are JSON with
    snake_case fields: amounts are integer minor units (cents) and timestamps
    are RFC 3339 in UTC. List endpoints are cursor-paginated. Errors return a
    small application/json envelope with a stable, machine-readable `code`.
servers:
  - url: https://api.finseed.es
security:
  - bearerAuth: []
paths:
  /v1/invoices/{id}/download:
    get:
      tags:
        - Invoices
      summary: Download an invoice PDF
      description: >-
        Returns a signed `download_url` you can hand straight to a browser to
        download the invoice PDF, so your API key never reaches the client. The
        link is a same-origin URL on the API host and stays valid for 24 hours,
        long enough to embed in a page; request a fresh one once it expires.
        This endpoint authenticates your integration, not your end users: it can
        reach every invoice in the key's environment, so check in your own app
        that the signed-in user may see this invoice before calling it.
      operationId: downloadInvoice
      parameters:
        - name: id
          in: path
          required: true
          description: Opaque invoice identifier — the `id` from a list row.
          schema:
            type: string
      responses:
        '200':
          description: A signed link to download the invoice PDF.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InvoiceDownload'
        '401':
          description: >-
            Authentication failed: the API key is missing, malformed, or
            revoked. Send a valid key as a bearer token in the `Authorization`
            header. Each key is bound to a single environment (test or live).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              example:
                code: unauthorized
                detail: >-
                  Authentication failed. Send your API key as a bearer token in
                  the `Authorization` header. Keys are scoped to one
                  environment, so a test key cannot read live data and vice
                  versa.
                errors: []
                doc_url: https://www.finseed.es/docs/api-reference/errors#unauthorized
        '404':
          description: >-
            No invoice matches the supplied identifier in the environment the
            API key belongs to. An invoice created with a live key is not
            visible to a test key, and vice versa.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              example:
                code: invoice_not_found
                detail: >-
                  No invoice matches that identifier in this environment. Note
                  that test and live keys see different invoices.
                errors: []
                doc_url: >-
                  https://www.finseed.es/docs/api-reference/errors#invoice_not_found
        '500':
          description: >-
            An unexpected error occurred on our side. No partial work is
            persisted, so the request can be retried safely.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              example:
                code: internal_error
                detail: >-
                  Something went wrong on our side. The request did not complete
                  and can be retried safely.
                errors: []
                doc_url: >-
                  https://www.finseed.es/docs/api-reference/errors#internal_error
components:
  schemas:
    InvoiceDownload:
      type: object
      properties:
        download_url:
          type: string
          description: >-
            Signed URL on the API host that returns the invoice PDF. Hand it
            straight to a browser to download the file. It stays valid for 24
            hours, so you can embed it in a page; request a fresh one once it
            expires.
          example: https://api.finseed.es/v1/invoices/inv_clx123abc456/file?token=…
        filename:
          type: string
          description: Suggested file name for the downloaded PDF.
          example: 2026-000123.pdf
        expires_at:
          type: string
          description: >-
            When download_url stops working, RFC 3339 in UTC. Request a fresh
            link after this.
          example: '2026-06-02T08:35:00Z'
      required:
        - download_url
        - filename
        - expires_at
      additionalProperties: false
      description: A signed link to download an invoice as a PDF.
      example:
        download_url: https://api.finseed.es/v1/invoices/inv_clx123abc456/file?token=…
        filename: 2026-000123.pdf
        expires_at: '2026-06-02T08:35:00Z'
    ErrorEnvelope:
      type: object
      properties:
        code:
          type: string
          description: >-
            Stable, machine-readable error code. The branch key. This is an
            extensible enum: new values may be added in the future, so clients
            must tolerate values not listed here. Known values: invalid_request,
            unauthorized, invoice_not_found, download_link_expired,
            number_series_not_found, number_series_prefix_taken,
            number_series_in_use, customer_not_found, customer_ambiguous,
            idempotency_conflict, rate_limited, invalid_number_series,
            invalid_tax_rate, invalid_tax_data, invalid_tax_id,
            tax_id_type_country_mismatch, insufficient_recipient_data,
            simplified_amount_exceeded, simplified_incompatible_tax_type,
            invalid_recargo_equivalencia, aeat_mandate_not_approved,
            no_active_subscription, tax_id_validation_unavailable,
            invalid_rectifies_reference, rectified_invoice_not_found,
            invoice_already_voided, invoice_already_replaced,
            invoice_not_family_tip, invoice_pending_at_aeat,
            invoice_not_rectifiable_at_aeat, family_balance_below_zero,
            replacement_total_negative, reason_incompatible_with_recipient,
            recipient_overrides_not_allowed_for_differences,
            rectifying_series_invalid, external_reference_invalid,
            external_reference_matches_existing_invoice,
            rectified_amounts_required_for_substitution,
            line_item_without_tax_items, internal_error.
          example: invalid_request
        detail:
          type: string
          description: Human-readable, context-specific explanation.
          example: The query parameters are not valid.
        errors:
          type: array
          items:
            type: object
            properties:
              field:
                type: string
                description: Location of the offending value (JSON path).
                example: limit
              code:
                type: string
                description: Machine-readable validation issue code.
                example: too_big
              message:
                type: string
                description: Human-readable explanation of the field-level issue.
                example: Number must be less than or equal to 100
            required:
              - field
              - code
              - message
            additionalProperties: false
          description: >-
            Field-level issues. Always present; empty unless this is a
            validation failure.
        doc_url:
          type: string
          description: Link to the reference documentation for this error code.
          example: https://www.finseed.es/docs/api-reference/errors#invalid_request
      required:
        - code
        - detail
        - errors
        - doc_url
      additionalProperties: false
      description: >-
        Uniform error body returned for every non-2xx response
        (application/json).
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: API key sent as a bearer token in the `Authorization` header.

````