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

# Upload Bulk Cross-Ramp Invoices

> Uploads the commercial invoices (Base64 PDFs) for several transactions of a bulk created without them. Each entry is processed on its own, in request order, and gets its own result: one rejected invoice never blocks the others. The response is 200 whenever the request itself is valid, so always read every entry of results. A transaction whose invoice is accepted moves from WAITING_INVOICE to PENDING_FUNDS; the bulk is processed only when every transaction has its invoice and is funded, and the single payout to the provider is placed at that moment in every country (for China and Hong Kong the supporting document is one PDF merged from all the bulk's invoices). The stored invoices of one bulk may total at most 24 MiB decoded and 500 pages: an entry that would go over is an ERROR with CROSS_RAMP_BULK_INVOICE_BUDGET_EXCEEDED or CROSS_RAMP_BULK_INVOICE_PAGES_EXCEEDED, nothing is stored and the transaction stays WAITING_INVOICE (retry with a smaller or shorter file; cancelled transactions free their share). Each file is parsed: an unreadable or encrypted PDF, or one with 0 or more than 500 pages, is an ERROR with INVALID_COMMERCIAL_INVOICE. An ERROR with CROSS_RAMP_BULK_INVOICE_SIZE_UNAVAILABLE is temporary: retry that entry after a short wait. If another invoice of the same bulk is being processed (the wait is about 2 seconds), the whole request fails with 503 CROSS_RAMP_BULK_INVOICE_BUSY and nothing is processed: wait a second or two and resend it. At most 25 entries and about 25 MiB of Base64 text per request: split larger sets across several requests. Envelope errors (400, 404) process nothing. Naturally idempotent: an invoice for a transaction that already passed the invoice step answers ALREADY_UPLOADED. This route does not support the Idempotency-Key header and requires bulk cross-ramp to be enabled for your environment.

Uploads the commercial invoices for several transactions of a [bulk cross-ramp](https://docs.capa.fi/reference/crossramppartnerv2controller_createpartnercrossrampbulk.md) that were created without one (status `WAITING_INVOICE`). Each invoice that is accepted moves its transaction to `PENDING_FUNDS`; read the transaction afterwards to get the `sourceBankAccount` the user needs to deposit.

> [!NOTE]
>
> Bulk cross-ramp is **enabled on request**, and so is this endpoint: until it is enabled for your environment it returns `404`.

> [!WARNING]
>
> The response is `200` whenever the request itself is valid, **even if some invoices failed**. Always read every entry of `results` and handle each `status`.

***

## Idempotency

This route does not support the `Idempotency-Key` header. It is naturally idempotent: an invoice for a transaction that already passed the invoice step is answered `ALREADY_UPLOADED` and nothing new is stored, so a failed or timed-out request can be sent again as is.

***

## Request

```json theme={null}
{
  "invoices": [
    { "transactionId": "3f6c1e0a-6d0b-4d4e-9a52-1b2f7d6e8c11", "invoiceFile": "JVBERi0xLjQK..." },
    { "transactionId": "8d1f0c3e-2b7a-4e55-9c1d-6a4f2e9b7c10", "invoiceFile": "JVBERi0xLjQK..." }
  ]
}
```

* `invoices`: between 1 and **25** entries per request, with no repeated `transactionId`.
* `transactionId`: a transaction of this bulk, as returned when the bulk was created.
* `invoiceFile`: Base64-encoded PDF, no whitespace, maximum 25 MB once decoded. Each file is parsed: an unreadable or encrypted PDF, or one with 0 or more than 500 pages, is an `ERROR` entry with `INVALID_COMMERCIAL_INVOICE`.
* The Base64 text of all the invoices together must stay under about **25 MiB**. Split larger sets across several requests.

## Response

```json theme={null}
{
  "success": true,
  "data": {
    "bulkId": "12a121ad-cbea-4ec4-9e0a-5c861e528bba",
    "results": [
      { "transactionId": "3f6c1e0a-6d0b-4d4e-9a52-1b2f7d6e8c11", "status": "UPLOADED" },
      { "transactionId": "8d1f0c3e-2b7a-4e55-9c1d-6a4f2e9b7c10", "status": "ALREADY_UPLOADED" },
      {
        "transactionId": "c2a9e4b1-5f3d-4a8e-8b6c-1d7e0f9a2b34",
        "status": "ERROR",
        "error": { "code": "USER_NOT_VERIFIED_ERROR", "message": "..." }
      }
    ]
  }
}
```

`results` has one entry per requested invoice, **in request order**.

| `status` | Meaning |
| - | - |
| `UPLOADED` | The invoice was accepted now; the transaction moved to `PENDING_FUNDS`. |
| `ALREADY_UPLOADED` | The transaction had already passed the invoice step. Nothing was stored. |
| `ERROR` | `error.code` and `error.message` say why. The transaction is unchanged and the entry can be retried. |

An `ERROR` entry carries the same codes as [Upload Cross-Ramp Invoice](https://docs.capa.fi/reference/crossramppartnerv2controller_uploadpartnercrossrampinvoice.md): `CROSS_RAMP_NOT_AWAITING_INVOICE`, `USER_NOT_VERIFIED_ERROR`, `SIGNATURE_REQUIREMENT_NOT_MET`, `INVALID_COMMERCIAL_INVOICE`, `COMMERCIAL_INVOICE_UPLOAD_FAILED`, and `INTERNAL_ERROR` for an unexpected failure. Three more apply to bulks:

| `error.code` | Meaning |
| - | - |
| `CROSS_RAMP_BULK_INVOICE_BUDGET_EXCEEDED` | The stored invoices of one bulk may total at most **24 MiB** (decoded), and this one would go over. Nothing is stored and the transaction stays `WAITING_INVOICE`; retry it with a smaller file. Cancelled transactions free their share. |
| `CROSS_RAMP_BULK_INVOICE_PAGES_EXCEEDED` | The stored invoices of one bulk may total at most **500 pages**, and this one would go over. Nothing is stored and the transaction stays `WAITING_INVOICE`; retry it with a shorter file. Cancelled transactions free their share. |
| `CROSS_RAMP_BULK_INVOICE_SIZE_UNAVAILABLE` | The size or page count of an invoice already stored for the bulk can't be read yet. Nothing is stored. Wait a moment and retry that entry. |

The request still answers `200` for these: retry only the failed entries.

If another invoice of the same bulk is being processed (it stays busy for about 2 seconds), the **whole request** fails with HTTP `503` `CROSS_RAMP_BULK_INVOICE_BUSY` and nothing is processed, not even entries that would have been rejected. Wait a second or two and resend the same request.

***

## Rules

* Entries are processed one by one, in order. A rejected invoice never blocks the others.
* A malformed request, one that names a transaction that is not part of the bulk, or one that finds the bulk busy (`503`), **processes nothing** and answers with an HTTP error (see below).
* The bulk is processed only when **every** transaction has its invoice and is funded. The single payout to the payment provider is placed at that moment, in every country; for China and Hong Kong the supporting document sent to the provider is one PDF merged from all the bulk's invoices.
* A transaction can also receive its invoice on its own with [Upload Cross-Ramp Invoice](https://docs.capa.fi/reference/crossramppartnerv2controller_uploadpartnercrossrampinvoice.md).
* Replacing an invoice that was already uploaded is not supported.

See the [Cross-Ramp guide](https://docs.capa.fi/docs/cross-ramp.md#upload-bulk-invoices) for the full flow.

***

## Error Codes

These errors apply to the whole request and process nothing. Errors of an individual invoice are returned inside `results` instead.

### Common Errors

| HTTP Status | Code | Message |
| - | - | - |
| 401 | `UNAUTHORIZED` | "API Key is missing" |
| 401 | `UNAUTHORIZED` | "Invalid API Key format" |
| 401 | `UNAUTHORIZED` | "Invalid API Key" |

### Endpoint-Specific Errors

| HTTP Status | Code | Message |
| - | - | - |
| 400 | `INVALID_USER_INPUT_ERROR` | "Invalid User Input" (`invoices` missing or empty, more than 25 entries, a repeated `transactionId`, an `invoiceFile` that is not Base64, or invoices above about 25 MiB of Base64 in total; the failing rule is in `errors[].message`) |
| 404 | `NOT_FOUND_ERROR` | "Cross ramp bulk {bulkId} was not found" (unknown bulk or another partner's bulk) |
| 404 | `CROSS_RAMP_BULK_ITEMS_NOT_FOUND` | "Transactions {ids} are not part of cross ramp bulk {bulkId}" |
| 404 | — | "Not Found": bulk cross-ramp is not enabled for this environment yet |
| 503 | `CROSS_RAMP_BULK_INVOICE_BUSY` | "Another invoice of this bulk is being processed; retry in a moment". Another upload of the same bulk held it for about 2 seconds. Nothing is processed; wait a second or two and resend the request |


## OpenAPI

````yaml reference/openapi/CrossRampPartnerV2Controller_uploadPartnerCrossRampBulkInvoices.json POST /api/partner/v2/cross-ramp/bulk/{bulkId}/invoices
openapi: 3.0.0
info:
  title: Capa Partner API - V2
  description: >-
    Partner API for integrating cryptocurrency on-ramp and off-ramp services
    using Capa's infrastructure. Enable your users to seamlessly convert between
    fiat and crypto.
  version: v2
  contact: {}
servers:
  - url: https://api.sandbox.capa.fi
  - url: https://api.capa.fi
security: []
paths:
  /api/partner/v2/cross-ramp/bulk/{bulkId}/invoices:
    post:
      tags:
        - cross-ramp
      summary: Upload Bulk Cross-Ramp Invoices
      description: >-
        Uploads the commercial invoices (Base64 PDFs) for several transactions
        of a bulk created without them. Each entry is processed on its own, in
        request order, and gets its own result: one rejected invoice never
        blocks the others. The response is 200 whenever the request itself is
        valid, so always read every entry of results. A transaction whose
        invoice is accepted moves from WAITING_INVOICE to PENDING_FUNDS; the
        bulk is processed only when every transaction has its invoice and is
        funded, and the single payout to the provider is placed at that moment
        in every country (for China and Hong Kong the supporting document is one
        PDF merged from all the bulk's invoices). The stored invoices of one
        bulk may total at most 24 MiB decoded and 500 pages: an entry that would
        go over is an ERROR with CROSS_RAMP_BULK_INVOICE_BUDGET_EXCEEDED or
        CROSS_RAMP_BULK_INVOICE_PAGES_EXCEEDED, nothing is stored and the
        transaction stays WAITING_INVOICE (retry with a smaller or shorter file;
        cancelled transactions free their share). Each file is parsed: an
        unreadable or encrypted PDF, or one with 0 or more than 500 pages, is an
        ERROR with INVALID_COMMERCIAL_INVOICE. An ERROR with
        CROSS_RAMP_BULK_INVOICE_SIZE_UNAVAILABLE is temporary: retry that entry
        after a short wait. If another invoice of the same bulk is being
        processed (the wait is about 2 seconds), the whole request fails with
        503 CROSS_RAMP_BULK_INVOICE_BUSY and nothing is processed: wait a second
        or two and resend it. At most 25 entries and about 25 MiB of Base64 text
        per request: split larger sets across several requests. Envelope errors
        (400, 404) process nothing. Naturally idempotent: an invoice for a
        transaction that already passed the invoice step answers
        ALREADY_UPLOADED. This route does not support the Idempotency-Key header
        and requires bulk cross-ramp to be enabled for your environment.
      operationId: CrossRampPartnerV2Controller_uploadPartnerCrossRampBulkInvoices
      parameters:
        - name: bulkId
          in: path
          required: true
          description: Bulk ID returned when the bulk was created.
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                invoices:
                  type: array
                  minItems: 1
                  maxItems: 25
                  description: >-
                    Invoices to attach, one per transaction of the bulk. At most
                    25 entries, no repeated transactionId, and about 25 MiB of
                    Base64 text in total.
                  items:
                    type: object
                    properties:
                      transactionId:
                        type: string
                        format: uuid
                        description: >-
                          ID of a transaction of this bulk, as returned when the
                          bulk was created.
                      invoiceFile:
                        type: string
                        description: >-
                          Base64-encoded PDF commercial invoice, no whitespace.
                          Maximum 25 MB once decoded. Parsed as a real PDF: an
                          unreadable or encrypted file, or one with 0 or more
                          than 500 pages, is an ERROR entry with
                          INVALID_COMMERCIAL_INVOICE.
                    required:
                      - transactionId
                      - invoiceFile
              required:
                - invoices
              x-readme-ref-name: UploadPartnerCrossRampBulkInvoicesV2RequestBody
            example:
              invoices:
                - transactionId: 3f6c1e0a-6d0b-4d4e-9a52-1b2f7d6e8c11
                  invoiceFile: JVBERi0xLjQK...
                - transactionId: 8d1f0c3e-2b7a-4e55-9c1d-6a4f2e9b7c10
                  invoiceFile: JVBERi0xLjQK...
      responses:
        '200':
          description: >-
            The request was well-formed. Each entry of results is UPLOADED,
            ALREADY_UPLOADED or ERROR (with a code and message); some entries
            may fail while others succeed. A failed entry leaves its transaction
            unchanged and can be retried. An entry that would take the stored
            invoices of the bulk above 24 MiB decoded or 500 pages is an ERROR
            with code CROSS_RAMP_BULK_INVOICE_BUDGET_EXCEEDED or
            CROSS_RAMP_BULK_INVOICE_PAGES_EXCEEDED;
            CROSS_RAMP_BULK_INVOICE_SIZE_UNAVAILABLE is temporary, retry those
            entries after a short wait.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    type: object
                    properties:
                      bulkId:
                        type: string
                        description: Bulk ID
                        example: 12a121ad-cbea-4ec4-9e0a-5c861e528bba
                      results:
                        type: array
                        description: >-
                          One result per requested invoice, in request order.
                          The request answers 200 even when some entries failed,
                          so always read each entry.
                        items:
                          type: object
                          properties:
                            transactionId:
                              type: string
                              example: 3f6c1e0a-6d0b-4d4e-9a52-1b2f7d6e8c11
                            status:
                              type: string
                              enum:
                                - UPLOADED
                                - ALREADY_UPLOADED
                                - ERROR
                              description: >-
                                UPLOADED: the invoice was accepted now.
                                ALREADY_UPLOADED: the transaction had already
                                passed the invoice step, so nothing was stored.
                                ERROR: see error; the transaction is unchanged
                                and the entry can be retried.
                            error:
                              type: object
                              description: >-
                                Present only when status is ERROR. Same codes as
                                Upload Cross-Ramp Invoice, e.g.
                                CROSS_RAMP_NOT_AWAITING_INVOICE,
                                USER_NOT_VERIFIED_ERROR,
                                SIGNATURE_REQUIREMENT_NOT_MET,
                                INVALID_COMMERCIAL_INVOICE,
                                COMMERCIAL_INVOICE_UPLOAD_FAILED,
                                CROSS_RAMP_BULK_INVOICE_BUDGET_EXCEEDED (bulk
                                invoices above 24 MiB decoded; retry with a
                                smaller file),
                                CROSS_RAMP_BULK_INVOICE_PAGES_EXCEEDED (bulk
                                invoices above 500 pages; retry with a shorter
                                file), CROSS_RAMP_BULK_INVOICE_SIZE_UNAVAILABLE
                                (temporary; retry after a short wait), or
                                INTERNAL_ERROR for an unexpected failure.
                              properties:
                                code:
                                  type: string
                                  example: CROSS_RAMP_NOT_AWAITING_INVOICE
                                message:
                                  type: string
                              required:
                                - code
                                - message
                          required:
                            - transactionId
                            - status
                    required:
                      - bulkId
                      - results
                    x-readme-ref-name: UploadCrossRampBulkInvoicesResponse
              example:
                success: true
                data:
                  bulkId: 12a121ad-cbea-4ec4-9e0a-5c861e528bba
                  results:
                    - transactionId: 3f6c1e0a-6d0b-4d4e-9a52-1b2f7d6e8c11
                      status: UPLOADED
                    - transactionId: 8d1f0c3e-2b7a-4e55-9c1d-6a4f2e9b7c10
                      status: ALREADY_UPLOADED
                    - transactionId: c2a9e4b1-5f3d-4a8e-8b6c-1d7e0f9a2b34
                      status: ERROR
                      error:
                        code: CROSS_RAMP_NOT_AWAITING_INVOICE
                        message: >-
                          Cross ramp c2a9e4b1-5f3d-4a8e-8b6c-1d7e0f9a2b34 is
                          CANCELLED and does not accept an invoice
        '400':
          description: Bad Request. Malformed request; nothing is processed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                INVALID_USER_INPUT_ERROR:
                  value:
                    success: false
                    code: INVALID_USER_INPUT_ERROR
                    message: Invalid User Input
                    errors:
                      - field: invoices
                        message: invoices must not repeat a transactionId
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                UNAUTHORIZED:
                  value:
                    success: false
                    code: UNAUTHORIZED
                    message: API Key is missing
                UNAUTHORIZED_2:
                  value:
                    success: false
                    code: UNAUTHORIZED
                    message: Invalid API Key format
                UNAUTHORIZED_3:
                  value:
                    success: false
                    code: UNAUTHORIZED
                    message: Invalid API Key
        '404':
          description: Not Found. Nothing is processed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                NOT_FOUND_ERROR:
                  value:
                    success: false
                    code: NOT_FOUND_ERROR
                    message: >-
                      Cross ramp bulk 12a121ad-cbea-4ec4-9e0a-5c861e528bba was
                      not found
                CROSS_RAMP_BULK_ITEMS_NOT_FOUND:
                  value:
                    success: false
                    code: CROSS_RAMP_BULK_ITEMS_NOT_FOUND
                    message: >-
                      Transactions c2a9e4b1-5f3d-4a8e-8b6c-1d7e0f9a2b34 are not
                      part of cross ramp bulk
                      12a121ad-cbea-4ec4-9e0a-5c861e528bba
        '503':
          description: >-
            Service Unavailable. Another invoice of the same bulk is being
            processed (the wait is about 2 seconds). Nothing is processed; wait
            a second or two and resend the request.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                CROSS_RAMP_BULK_INVOICE_BUSY:
                  value:
                    success: false
                    code: CROSS_RAMP_BULK_INVOICE_BUSY
                    message: >-
                      Another invoice of this bulk is being processed; retry in
                      a moment
      security:
        - PartnerApiKey: []
components:
  schemas:
    ErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          example: false
        code:
          type: string
          description: Machine-readable error code.
        message:
          type: string
          description: Human-readable error message.
        errors:
          type: array
          description: Optional per-field validation details.
          items:
            type: object
            properties:
              field:
                type: string
              message:
                type: string
      required:
        - success
        - code
        - message
  securitySchemes:
    PartnerApiKey:
      type: apiKey
      in: header
      name: partner-api-key
      description: API key for the affiliated partner performing the request.

````

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