> ## Documentation Index
> Fetch the complete documentation index at: https://vexioncards.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# List invoices

> Returns issued subscription invoices, newest first, cursor-paginated (default 25, max 100).

Optional filters: `status` (e.g. `paid`, `open`, `credit_note`), `from` / `to` (issued_at range).

Each invoice carries a `pdf_url` - a **signed short-TTL URL (1 hour)**. Download promptly; the url itself expires per S3's own presigned-URL rules - an expired link returns S3's own `403 Forbidden` (an XML body, not the VEXiON JSON error envelope, since the request goes straight to S3 and never reaches this API). There is no dedicated VEXiON error code for this; re-fetch the invoice via this endpoint (or `GET /v1/organization/invoices/{id}`) for a fresh `pdf_url`. Amounts are in MAJOR units (mirroring the human invoice document).

**Scope: `organization:read`.** Added 2026-07-27 (owner-approved versioned API change). This endpoint used to require no scope at all: any valid key for the organization, whatever scopes it carried, could read this organization's invoice history, including amounts, VAT, payment method and refunds - a key minted only for, say, `notifications:send` could still read it. That gap is now closed. Existing keys minted before 2026-07-27 were backfilled with `organization:read` so no working integration broke when enforcement landed.



## OpenAPI

````yaml /openapi.json get /v1/organization/invoices
openapi: 3.1.0
info:
  title: VEXiON cards Public API
  description: >-
    ## Rate limiting


    Two independent layers, checked in this order:


    1. **Per-IP throttle (pre-authentication).** Applied to every `/v1` request
    BEFORE the API key is checked, keyed on the caller's IP address:
       - **600 requests/minute** per IP - a flood ceiling, `429 rate_limit_error` / `rate_limited`.
       - **20 failed authentications per 15 minutes** per IP - a key-guessing ceiling. Only responses that are `401` (missing/invalid/revoked key) count against this ceiling; a `403` from a valid key that simply lacks a scope does not. `429 rate_limit_error` / `too_many_failed_attempts`.

       Both ceilings send `Retry-After` (seconds).
    2. **Per-key, per-bucket limiter (post-authentication).** Documented per
    endpoint (see each operation's `429` response and the `rate_limit` field on
    the API Key resource) - e.g. 60/min default, 120/min for transactions, plus
    the notification-broadcast and lookup-filter buckets described on their own
    endpoints.


    ### Rate-limit response headers


    Every rate-limited response carries the legacy `X-RateLimit-Limit` /
    `X-RateLimit-Remaining` / `X-RateLimit-Reset` family (the last is an **epoch
    timestamp**) AND the IETF standards-track headers, side by side:


    - `RateLimit-Policy: "<bucket>";q=<quota>;w=<window seconds>` - the static
    policy for the bucket that was hit.

    - `RateLimit: "<bucket>";r=<remaining>;t=<seconds until reset>` - live
    state. **`t` is a DURATION (seconds remaining), not the epoch timestamp
    `X-RateLimit-Reset` carries - the two are never the same value.**
  version: 1.0.0
servers:
  - url: https://api.vexioncards.one
    description: Production
  - url: https://migration.api.vexioncards.one
    description: Sandbox
security:
  - apiKey: []
tags:
  - name: Customers
  - name: Cards
  - name: Transactions
  - name: Notifications
  - name: Locations
  - name: Products
  - name: API keys
  - name: Organization
  - name: Webhook endpoints
  - name: Events
  - name: Custom fields
  - name: Team members
  - name: Icons
paths:
  /v1/organization/invoices:
    get:
      tags:
        - Organization
      summary: List invoices
      description: >-
        Returns issued subscription invoices, newest first, cursor-paginated
        (default 25, max 100).


        Optional filters: `status` (e.g. `paid`, `open`, `credit_note`), `from`
        / `to` (issued_at range).


        Each invoice carries a `pdf_url` - a **signed short-TTL URL (1 hour)**.
        Download promptly; the url itself expires per S3's own presigned-URL
        rules - an expired link returns S3's own `403 Forbidden` (an XML body,
        not the VEXiON JSON error envelope, since the request goes straight to
        S3 and never reaches this API). There is no dedicated VEXiON error code
        for this; re-fetch the invoice via this endpoint (or `GET
        /v1/organization/invoices/{id}`) for a fresh `pdf_url`. Amounts are in
        MAJOR units (mirroring the human invoice document).


        **Scope: `organization:read`.** Added 2026-07-27 (owner-approved
        versioned API change). This endpoint used to require no scope at all:
        any valid key for the organization, whatever scopes it carried, could
        read this organization's invoice history, including amounts, VAT,
        payment method and refunds - a key minted only for, say,
        `notifications:send` could still read it. That gap is now closed.
        Existing keys minted before 2026-07-27 were backfilled with
        `organization:read` so no working integration broke when enforcement
        landed.
      operationId: listOrganizationInvoices
      parameters:
        - name: limit
          in: query
          description: >-
            Cursor pagination page size. Default 25, max 100. Values outside
            1-100 are rejected with `400 invalid_limit`, not clamped.
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
        - name: starting_after
          in: query
          description: >-
            Cursor for forward pagination; the id of the last item from the
            previous page. Mutually exclusive with ending_before. Numeric offset
            or page parameters are not supported; cursors are the only supported
            paging mechanism.
          required: false
          schema:
            type: string
        - name: ending_before
          in: query
          description: >-
            Cursor for reverse pagination; the id of the first item from the
            previous page. Mutually exclusive with starting_after.
          required: false
          schema:
            type: string
        - name: status
          in: query
          description: >-
            Filter by invoice status (`paid`, `open`, `pending`,
            `requires_billing_details`, `failed`, `refunded`, `credit_note`).
          required: false
          schema:
            type: string
            enum:
              - paid
              - open
              - pending
              - requires_billing_details
              - failed
              - refunded
              - credit_note
        - name: issued[gte]
          in: query
          required: false
          description: Lower bound on issued_at - unix seconds or ISO-8601 (inclusive).
          schema:
            anyOf:
              - type: integer
                title: Unix seconds
              - type: string
                format: date-time
                title: ISO-8601
          example: 1780000000
        - name: issued[lte]
          in: query
          required: false
          description: Upper bound on issued_at - unix seconds or ISO-8601 (inclusive).
          schema:
            anyOf:
              - type: integer
                title: Unix seconds
              - type: string
                format: date-time
                title: ISO-8601
      responses:
        '200':
          description: Paged invoices.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InvoiceList'
              examples:
                Paid invoices:
                  summary: One paid invoice
                  value:
                    object: list
                    data:
                      - id: inv_01HXYZINV001
                        object: invoice
                        number: '2026000147'
                        status: paid
                        paid: true
                        amount: 45
                        amount_paid: 45
                        vat_amount: 8.42
                        vat_rate: 23
                        reverse_charge: false
                        currency: EUR
                        presentment_currency: null
                        presentment_amount: null
                        payment_method: card
                        issued_at: 1780460353
                        paid_at: 1780460355
                        pdf_url: >-
                          https://files.vexioncards.one/invoices/2026/VEX-2026000147.pdf?sig=abc&exp=1780464000
                        refunded_amount: 0
                        refunded_at: null
                        refund_reason: null
                        corrects_invoice_id: null
                        corrected_by_invoice_id: null
                        location_id: null
                        created_at: 1780460353
                    has_more: false
                    url: /v1/organization/invoices
                Credit note:
                  summary: Refund issued as credit note
                  value:
                    object: list
                    data:
                      - id: inv_01HXYZINV002
                        object: invoice
                        number: D2026000012
                        status: credit_note
                        paid: false
                        amount: -45
                        amount_paid: 0
                        vat_amount: 8.42
                        vat_rate: 23
                        reverse_charge: false
                        currency: EUR
                        presentment_currency: null
                        presentment_amount: null
                        payment_method: card
                        issued_at: 1780460353
                        paid_at: 1780460355
                        pdf_url: >-
                          https://files.vexioncards.one/invoices/2026/VEX-2026000147.pdf?sig=abc&exp=1780464000
                        refunded_amount: 0
                        refunded_at: null
                        refund_reason: null
                        corrects_invoice_id: inv_01HXYZINV001
                        corrected_by_invoice_id: null
                        location_id: null
                        created_at: 1780460353
                    has_more: false
                    url: /v1/organization/invoices
          headers: {}
        '400':
          description: >-
            Invalid pagination parameter: limit outside 1-100, or a malformed
            cursor.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                Invalid limit:
                  summary: limit out of range
                  value:
                    error:
                      type: invalid_request_error
                      code: invalid_limit
                      message: limit must be an integer between 1 and 100.
                      doc_url: >-
                        https://vexioncards.mintlify.site/api-reference/errors#invalid_limit
                      request_id: req_5f8b2c4a9e1d3
                      param: limit
                Malformed cursor:
                  summary: starting_after is not a valid cursor
                  value:
                    error:
                      type: invalid_request_error
                      code: invalid_cursor
                      message: starting_after is not a valid inv_ cursor.
                      doc_url: >-
                        https://vexioncards.mintlify.site/api-reference/errors#invalid_cursor
                      request_id: req_5f8b2c4a9e1d3
                      param: starting_after
          headers: {}
        '401':
          description: Missing, invalid, or revoked API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: API key lacks the `organization:read` scope (added 2026-07-27).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Rate limited - respect Retry-After.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Server error. Retry-safe on idempotent calls.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  type: api_error
                  code: internal_error
                  message: >-
                    An internal error occurred. The request may be retried with
                    the same Idempotency-Key.
                  doc_url: >-
                    https://vexioncards.mintlify.site/api-reference/errors#internal_error
                  request_id: req_5f8b2c4a9e1d3
              examples:
                Http 500 default:
                  summary: Http 500 default
                  value:
                    error:
                      type: api_error
                      code: internal_error
                      message: >-
                        An internal error occurred. The request may be retried
                        with the same Idempotency-Key.
                      doc_url: >-
                        https://vexioncards.mintlify.site/api-reference/errors#internal_error
                      request_id: req_5f8b2c4a9e1d3
          headers: {}
      deprecated: false
components:
  schemas:
    InvoiceList:
      allOf:
        - $ref: '#/components/schemas/ListEnvelope'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/Invoice'
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - type
            - code
            - message
          properties:
            type:
              type: string
              enum:
                - invalid_request_error
                - authentication_error
                - permission_error
                - not_found_error
                - rate_limit_error
                - idempotency_error
                - api_error
            code:
              type: string
            message:
              type: string
            retry_after:
              type: integer
              description: >-
                Seconds to wait before retrying. Present on rate-limit (429)
                errors and on the retryable 409 conflicts
                (`idempotency_key_in_use`, `create_in_progress`,
                `concurrent_update`); mirrors the `Retry-After` HTTP header.
                Absent on error types that carry no retry guidance.
              example: 5
            param:
              type:
                - string
                - 'null'
            request_id:
              type: string
            doc_url:
              type: string
              format: uri
            field_errors:
              type: array
              description: >-
                Per-field errors on a 422. At most 100 entries: a request with
                more errors gets the first 100.
              items:
                type: object
                properties:
                  param:
                    type: string
                  code:
                    type: string
                  message:
                    type: string
                  expected_currency:
                    type: string
                    description: >-
                      On `currency_mismatch`: the business currency the request
                      must use. Absent on every other field error.
          description: >-
            The error payload: type (category), code (machine-readable), message
            (human-readable), retry_after (seconds, on rate-limit errors and
            retryable 409 conflicts only), param (offending field), request_id,
            doc_url, field_errors[].
      description: >-
        Standard error envelope. Branch on `error.code`; include
        `error.request_id` in support requests. See the Errors guide.
    ListEnvelope:
      type: object
      required:
        - object
        - data
        - has_more
      properties:
        object:
          type: string
          const: list
          description: Always `"list"`.
        data:
          type: array
          items: {}
          description: Array of the requested resource type.
        has_more:
          type: boolean
          description: >-
            True when more pages exist - pass the last item id as
            `starting_after`.
        next_cursor:
          type:
            - string
            - 'null'
          description: >-
            Cursor for the next page **in the direction you are already
            paging**, or `null` when this page ends the collection. `has_more:
            true` always comes with a non-null `next_cursor`.


            Feed it back to the SAME parameter you used: `starting_after` when
            paging forward (the default), or `ending_before` when paging
            backward. Treat it as opaque and do not parse it.


            You no longer need to take the last object's `id` yourself. That
            still works and is unchanged, but deriving the cursor from the page
            put the burden of knowing the sort direction on you, and it broke
            silently on any endpoint whose cursor is not the object id.
          example: cus_iofv5j4hn6bphinmmyat27tc5y
        url:
          type: string
          description: Stable collection URL.
      description: >-
        Standard cursor-pagination envelope for list endpoints. See the
        Pagination guide.
    Invoice:
      type: object
      description: >-
        An issued subscription invoice. Amounts are in MAJOR units of `currency`
        (this resource mirrors the human invoice document - unlike loyalty
        mechanics, which use minor units). PDF download via short-TTL signed
        URL.
      required:
        - id
        - object
        - status
        - paid
        - amount
        - currency
        - issued_at
        - created_at
      properties:
        id:
          type: string
          pattern: ^inv_[A-Za-z0-9]+$
          description: Invoice identifier (`inv_` prefix).
          example: inv_01HXYZINV001
        object:
          type: string
          const: invoice
          description: Always `"invoice"`.
        number:
          type:
            - string
            - 'null'
          description: >-
            Invoice number as issued. Null while the invoice has not been issued
            yet (`requires_billing_details`, `failed`).
          example: '2026000147'
        status:
          type: string
          enum:
            - paid
            - open
            - pending
            - requires_billing_details
            - failed
            - refunded
            - credit_note
          description: >-
            Invoice lifecycle. `requires_billing_details` = issuance blocked
            until the merchant completes billing identity. `credit_note` = a
            correcting document pointing at the original via
            `corrects_invoice_id`.
          example: paid
        paid:
          type: boolean
          description: Convenience flag aligned with `status`.
          example: true
        amount:
          type: number
          description: >-
            Gross total in MAJOR units (45.0 = €45.00) - the Invoice resource is
            the ONE documented exception to the minor-units convention: it
            mirrors the human invoice document (see doc conventions R4).
          example: 45
        amount_paid:
          type: number
          description: >-
            Amount actually charged to the payment method, MAJOR units (same
            documented exception as `amount` above). NOTE: an invoice fully
            covered by account credit is `paid` with `amount_paid: 0` - check
            `status`, not this number, for settlement.
          example: 45
        vat_amount:
          type: number
          description: >-
            VAT portion, MAJOR units (same documented exception as `amount`
            above).
          example: 8.42
        vat_rate:
          type: number
          description: VAT rate percentage applied.
          example: 23
        reverse_charge:
          type: boolean
          description: >-
            True for intra-EU reverse-charge invoices (VAT 0, customer
            self-accounts).
          example: false
        currency:
          type: string
          description: >-
            ISO 4217 invoice currency: EUR, or CZK for a business billed on the
            fixed Czech crown price list. Independent of the business currency
            of your loyalty cards.
          example: EUR
        presentment_currency:
          type:
            - string
            - 'null'
          description: >-
            Customer-facing currency for non-EUR adaptive pricing. Null when
            invoiced directly in EUR.
        presentment_amount:
          type:
            - number
            - 'null'
          description: Amount in `presentment_currency`. Null when not applicable.
        payment_method:
          type: string
          enum:
            - card
            - bank_transfer
          description: Neutral channel descriptor - independent of any payment processor.
          example: card
        issued_at:
          type: integer
          description: >-
            Unix seconds of invoice issuance (when the numbered document was
            generated).
          example: 1780460353
        paid_at:
          type:
            - integer
            - 'null'
          description: Unix seconds of settlement. Null while unpaid.
          example: 1780460355
        pdf_url:
          type: string
          format: uri
          description: >-
            Signed download URL for the PDF (1-hour TTL - fetch fresh from this
            endpoint when the link expires; do not store the URL, store the
            invoice id).
          example: >-
            https://files.vexioncards.one/invoices/2026/VEX-2026000147.pdf?sig=abc&exp=1780464000
        refunded_amount:
          type: number
          description: >-
            Refunded portion, MAJOR units (same documented exception as `amount`
            above). 0 when never refunded.
          example: 0
        refunded_at:
          type:
            - integer
            - 'null'
          description: Unix seconds of the refund. Null when never refunded.
        refund_reason:
          type:
            - string
            - 'null'
          description: Merchant-visible refund reason. Null when never refunded.
        corrects_invoice_id:
          type:
            - string
            - 'null'
          description: 'On credit notes: the original invoice this document corrects.'
        corrected_by_invoice_id:
          type:
            - string
            - 'null'
          description: 'On originals: the credit note that corrected this invoice.'
        location_id:
          type:
            - string
            - 'null'
          description: >-
            Populated for per-location franchise invoices. Null for org-level
            invoices.
        created_at:
          type: integer
          description: Unix seconds.
          example: 1780460353
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      description: >-
        Your secret API key as a Bearer token: `Authorization: Bearer
        vxn_sk_...`. Keys are created and scoped in the dashboard - see
        [Authentication](/api-reference/introduction#authentication).

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.