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

# Upload Document

> Upload a B2B services file — the commercial invoice, or a delivery proof after settlement — and get back a ref.

## Overview

Uploads one file for a B2B services payment and answers with a **`ref`**. What you do with that `ref` depends on which of the two document steps you are in:

| You uploaded                                | You then                                    | With                                                                             |
| ------------------------------------------- | ------------------------------------------- | -------------------------------------------------------------------------------- |
| the commercial invoice                      | send the `ref` under its checklist code     | [Submit Verification Details](/api-reference/v3/b2b/submit-verification-details) |
| a delivery proof, after the payment settles | send the `ref` in the settlement submission | [Submit Settlement Documents](/api-reference/v3/b2b/submit-settlement)           |

```json theme={null}
{ "documents": [{ "code": "invoice", "ref": "8207383264" }] }
```

<Note>
  **Two calls, not one.** Uploading a file does not answer a requirement; it stores a file. The requirement is answered when a later call names the `ref`. That separation is what lets the same upload endpoint serve both the verification step and the post-settlement one — and it is why neither step needs a draft of its own. An upload is durable, so a `ref` you are holding is your draft.
</Note>

## Classify the payment first

The `type` you may send depends on which flow the payment is in, so the payment has to be in one. A VBA credit arrives unclassified, and until you have sent its `business_model` and `purpose_code` through [Submit Verification Details](/api-reference/v3/b2b/submit-verification-details) an upload is refused:

```json theme={null}
{
  "success": false,
  "error": {
    "code": 40359,
    "message": "Invalid verification request.",
    "details": "Invalid verification request. This payment has no verification checklist, so there is no set of document types to accept; send the order's business model and purpose code first."
  }
}
```

Send the pair once and every later upload on that payment is routed for you. [Get Verification Requirements](/api-reference/v3/b2b/verification-requirements) tells you whether a payment is still waiting on it.

<Note>
  **The message names no flow, because there is not one yet.** Every other refusal on a classified services payment reads `Invalid B2B services request.` This one cannot: the classification is exactly what is missing, so naming a flow would be a guess. The code is `40359` either way.
</Note>

## The request

`multipart/form-data`, two parts:

| Part   |                                                           |
| ------ | --------------------------------------------------------- |
| `file` | The document itself.                                      |
| `type` | What kind of document it is — one of the two codes below. |

The path resolves the payment before anything is stored, under the same ownership rules as the verification endpoint: your own payments, and your sub-merchants'.

<Note>
  **PSPs send `X-Merchant-ID`**, naming the settling sub-merchant, exactly as on the verification endpoints.
</Note>

## Document types

B2B services uses two, and takes no others:

| `type`           |                                                                                                                           | Where it goes                    |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
| `invoice`        | Commercial invoice                                                                                                        | The verification checklist       |
| `delivery_proof` | Evidence the service was delivered — a signed acceptance note, a milestone sign-off, a delivery confirmation, a timesheet | The post-settlement document set |

The `type` decides where the file is stored, so it also decides which call can cite the resulting `ref`: an `invoice` ref is citable on [Submit Verification Details](/api-reference/v3/b2b/submit-verification-details), a `delivery_proof` ref in `refs` on [Submit Settlement Documents](/api-reference/v3/b2b/submit-settlement). Cite one on the other call and it reads as unknown — `ERR_B2B_SETTLEMENT_001` on the settlement submit, `Unknown document ref.` on the verification one.

A `type` outside these two — including document codes other flows define, such as `passport` — is refused:

```json theme={null}
{
  "success": false,
  "error": {
    "code": 40359,
    "message": "Invalid B2B services request.",
    "details": { "type": "Unknown document type for this payment's flow; send one of: delivery_proof, invoice." }
  }
}
```

<Warning>
  **`delivery_proof` is not a checklist item.** It never appears in [Get Verification Requirements](/api-reference/v3/b2b/verification-requirements), because it is owed *after* settlement rather than before it. Do not go looking for it there.
</Warning>

## The file

Validated on upload, so a bad file fails here rather than at submit time.

|                   |                                                                                    |
| ----------------- | ---------------------------------------------------------------------------------- |
| Extensions        | `pdf` · `png` · `jpg` · `jpeg` · `docx` · `xlsx` · `csv`                           |
| Maximum size      | 10 MB                                                                              |
| Maximum file name | 100 characters, extension included                                                 |
| Encrypted PDFs    | Rejected — a password-protected file cannot be read by anyone who has to review it |

<Warning>
  **A file name over 100 characters answers `500`, not `400`.** The envelope carries `40359`, and `details` is a stringified object holding the real reason — `File name must be less than 100 characters.`, code `40296`. It is your input that is wrong, not our service, so rename the file and upload it again rather than retrying. Truncate long names before uploading and you will never see it.
</Warning>

## The response

`201`, with the `ref`:

```json theme={null}
{
  "success": true,
  "message": "Document uploaded",
  "data": {
    "ref": "8207383264",
    "type": "invoice"
  }
}
```

<ParamField path="ref" type="string" required>
  The stored document's identifier. Send it as `documents[].ref` on the verification submit, or in `refs` on the settlement submit.

  The file is stored against **the payment in the path**, so the `ref` is only citable from that payment. A `ref` from one of your other payments reads as unknown, exactly as a made-up one does — the answer never distinguishes the two.
</ParamField>

<ParamField path="type" type="string" required>
  Echoes the `type` you sent.
</ParamField>

## Uploading more than one

**Both types accumulate.** Every upload adds its own row and returns its own `ref`; nothing supersedes anything, and an earlier `ref` stays valid.

**Invoices.** A payment may carry several — an amended invoice beside the original, or a job billed across two. You only cite the `invoice` code once on [Submit Verification Details](/api-reference/v3/b2b/submit-verification-details); the citation names the code, so **every invoice on the payment is filed** when the set completes. A second invoice needs no citation of its own.

<Warning>
  **There is no way to remove an invoice you uploaded by mistake.** It stays on the payment and is filed with the rest. Upload only what you want ops to see.
</Warning>

**Delivery proofs.** Collect them as they arrive, including before the payment settles. Nothing is filed until you [submit](/api-reference/v3/b2b/submit-settlement), and `refs` on that call is the whole set — a proof you would rather not file is one you leave out, and it is dropped. That is the settlement step's way of undoing an upload; the verification step has no equivalent.

Once the settlement set is submitted it is locked. A further `delivery_proof` upload is refused with `ERR_B2B_SETTLEMENT_002`.

## No waivers on this flow

Some checklists let a document be discharged with a `waiver_reason` instead of a file. **The B2B services checklist has no waivable item** — the commercial invoice is required, and there is nothing to waive. A `waiver_reason` sent on this flow is a `400`.

## Related

<CardGroup cols={2}>
  <Card title="Get Verification Requirements" icon="list-check" href="/api-reference/v3/b2b/verification-requirements">
    What this payment actually needs.
  </Card>

  <Card title="Submit Verification Details" icon="paper-plane" href="/api-reference/v3/b2b/submit-verification-details">
    Where the `ref` is bound to a checklist code.
  </Card>

  <Card title="Submit Settlement Documents" icon="lock" href="/api-reference/v3/b2b/submit-settlement">
    Where `delivery_proof` refs are filed, after settlement.
  </Card>

  <Card title="B2B Services Verification" icon="book" href="/integration-guide/v3/web-integration/b2b-services-verification">
    The whole flow, in order.
  </Card>
</CardGroup>


## OpenAPI

````yaml POST /pg/payments/{payment_id}/documents/
openapi: 3.0.0
info:
  title: Eximpe Payment Gateway API
  description: >-
    API for payment processing and order management through Eximpe payment
    gateway. This specification is for v3 API version.
  license:
    name: Proprietary
  version: 3.0.0
servers:
  - url: https://api-pacb-uat.eximpe.com
    description: Payment Gateway Sandbox URL
security:
  - clientAuth: []
    clientSecretAuth: []
    apiVersionHeader: []
tags:
  - name: Card Tokens
  - name: Merchants
  - name: Orders
  - name: Payment Links
  - name: Payments
  - name: Refunds
  - name: Settlements
  - name: Subscriptions
  - name: Virtual Bank Accounts
    description: Create and manage virtual bank accounts and read collected payments.
  - name: B2B Verification
    description: Verification and post-settlement compliance for B2B payments.
paths:
  /pg/payments/{payment_id}/documents/:
    post:
      tags:
        - LRS
      summary: Upload a supporting document
      description: >-
        Uploads one supporting file for a payment's verification and answers
        with a `ref`. Send that `ref` under the document's checklist code in the
        `documents` array of [Submit Verification
        Details](/api-reference/v3/lrs/submit-verification-details) — uploading
        a file does not answer a requirement; the submit does.


        Upload each file as it arrives; nothing has to be held back until the
        set is complete. Extension, size (10 MB) and PDF encryption are
        validated here, so a bad file fails on upload rather than at submit
        time.


        The path resolves the payment before anything is stored, under the same
        ownership rules as the verification endpoint. The stored document itself
        is merchant-scoped, so a `ref` stays valid across a retried attempt or a
        recurring installment, and a `ref` that is not yours reads as unknown
        rather than as someone else's file. Uploads are immutable — to replace
        one, upload again and submit the new `ref` under the same code.


        `POST /pg/lrs/documents/` predates this route and still works as an
        alias; new integrations should use this one.


        **PSP callers must send `X-Merchant-ID`.** This is a
        `multipart/form-data` request.
      operationId: v3_post_pg_payments_payment_id_documents_
      parameters:
        - name: payment_id
          in: path
          required: true
          schema:
            type: string
          description: UID of the payment the document is for.
          example: PR6938527534
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - file
                - type
              properties:
                file:
                  type: string
                  format: binary
                  description: >-
                    The document file. Allowed extensions: pdf, png, jpg, jpeg,
                    docx, xlsx, csv. Maximum 10 MB. Password-protected PDFs are
                    rejected.
                type:
                  type: string
                  description: >-
                    Document type — one of the codes the checklists ask for, so
                    the value you upload under is the value you submit under.
                    Read the ones this payment actually needs from [Get
                    Verification
                    Requirements](/api-reference/v3/lrs/verification-requirements)
                    rather than mapping this list into your code: it is the
                    complete set any checklist can ask for, and it grows as the
                    regulatory matrix is revised. `delivery_proof` is the one
                    type here that no checklist asks for: it is a
                    post-settlement compliance document, uploaded through this
                    endpoint and then filed by `ref` through [Submit
                    post-settlement
                    documents](/api-reference/v3/b2b/submit-settlement).
                  enum:
                    - offer_letter
                    - passport
                    - student_id_or_visa
                    - student_id
                    - fee_invoice
                    - passenger_list
                    - traveller_passports
                    - traveller_visas
                    - ticket
                    - invoice
                    - relationship_declaration
                    - delivery_proof
                  example: offer_letter
      responses:
        '201':
          description: Document uploaded.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  message:
                    type: string
                    example: Document uploaded
                  data:
                    type: object
                    properties:
                      ref:
                        type: string
                        description: >-
                          Reference to pass as `documents[].ref` on Submit
                          Verification Details.
                        example: '8207383264'
                      type:
                        type: string
                        example: offer_letter
              example:
                success: true
                message: Document uploaded
                data:
                  ref: '8207383264'
                  type: offer_letter
        '400':
          description: >-
            The payment id does not resolve for this caller, or the file is not
            an accepted type. `error.message` names the payment's flow — an LRS
            payment reads "Invalid LRS request.", a B2B services payment
            "Invalid B2B services request.", and a payment nothing has
            classified yet "Invalid verification request." The code is the same
            either way, so branch on the code.
          content:
            application/json:
              schema:
                type: object
              examples:
                payment_not_found:
                  summary: The payment id is unknown, or belongs to another merchant
                  value:
                    success: false
                    error:
                      code: 40360
                      message: >-
                        Payment is not in a state that accepts verification
                        details.
                      details: >-
                        Payment is not in a state that accepts verification
                        details. Payment not found.
                bad_file:
                  summary: The document type is not one this API accepts
                  value:
                    success: false
                    error:
                      code: 40359
                      message: Invalid LRS request.
                      details:
                        type: Unknown document type.
        '500':
          description: Unexpected error uploading the document.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/v3_ErrorResponse'
      security:
        - clientAuth: []
          clientSecretAuth: []
          merchantAuth: []
          apiVersionHeader: []
components:
  schemas:
    v3_ErrorResponse:
      type: object
      required:
        - success
        - error
      properties:
        success:
          type: boolean
          description: Indicates if the request was successful
        error:
          $ref: '#/components/schemas/v3_ErrorDetails'
    v3_ErrorDetails:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: string
          description: Error code (e.g., ERR_ORDER_002)
        message:
          type: string
          description: Error message
        details:
          type: object
          description: Detailed validation error information with field-specific errors
          additionalProperties:
            type: string
            description: Error message for the specific field
  securitySchemes:
    clientAuth:
      type: apiKey
      name: X-Client-ID
      in: header
      description: >-
        **Client Application ID** - Your unique application identifier used to
        authenticate API requests. You can find your Client ID in the Developer
        Settings section of the merchant dashboard.
      x-displayName: Client ID
      x-example: your-client-id
    clientSecretAuth:
      type: apiKey
      name: X-Client-Secret
      in: header
      description: >-
        **Client Secret Key** - Your secret key used alongside the Client ID for
        secure authentication. Keep this confidential and never expose it in
        client-side code. Available in the Developer Settings section of the
        merchant dashboard.
      x-displayName: Client Secret
      x-example: your-client-secret
    apiVersionHeader:
      type: apiKey
      name: X-API-Version
      in: header
      description: >-
        **API Version** - Specifies which version of the API to use (e.g.,
        '1.X.X', '2.X.X', or '3.X.X'). This header allows you to control which
        API version your integration uses. Default version information is
        available in the Developer Settings.
      x-displayName: API Version
      x-example: 3.0.0
    merchantAuth:
      type: apiKey
      name: X-Merchant-ID
      in: header
      description: >-
        **Merchant Identifier** - The unique ID for the merchant account. This
        is required for PSP (Payment Service Provider) merchants who manage
        multiple merchant accounts. You can find merchant IDs in the Merchant
        Management section of the dashboard.
      x-displayName: Merchant ID
      x-example: your-merchant-id

````