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

# Upload verification documents

> Upload the customer's documents as `multipart/form-data`. Send at least one of `id_front`, `id_back`, `proof_of_address` or `tax_document`.

**Submit the customer's personal data first.** Until [`POST /organization/{organizationId}/verification`](/v2/api-reference/kyc/submit-verification-data) has run the customer has no stages to upload against, so this answers `409`.

**Answers `202`, not `200`.** We read and check every part before we answer, and send the upload to the verification provider after. Watch [`GET /organization/{organizationId}/kyc?requirements=true`](/v2/api-reference/kyc/get-kyc-status) for the requirement to go satisfied.

**Upload what the current stage asks for.** Send a document once its requirement is listed. The exception is `proof_of_address`: you may send it with the identity document, before its own stage, as long as the identity stage has not been submitted yet. After that, wait for `proofOfAddress` to be listed. See [Requirements unlock in stages](/v2/guides/onboarding#requirements-unlock-in-stages).



## OpenAPI

````yaml openapi-v2.json POST /organization/{organizationId}/verification/documents
openapi: 3.1.0
info:
  title: Etherfuse FX API
  description: >-
    Partner-facing ramp API, version 2: payment accounts, quotes, orders and
    webhooks.
  license:
    name: Proprietary
  version: 2.0.0
servers:
  - url: https://api.sand.etherfuse.com
    description: Sandbox
security:
  - ApiKeyAuth: []
tags:
  - name: Payment Accounts
    description: >-
      Register the bank accounts and wallets that money moves from and to, and
      read their readiness per rail.
  - name: Quotes
    description: Price a transfer between two registered payment accounts.
  - name: Orders
    description: Create orders from quotes and track them.
  - name: Webhook Subscriptions
    description: Subscribe to webhook events.
  - name: Webhook Events
    description: Payloads Etherfuse sends to your webhook subscriptions.
  - name: Sandbox
    description: Endpoints that work only in sandbox, for testing.
  - name: Assets
    description: The markets and tokens a quote can use, and the balances of a wallet.
  - name: Authentication
    description: >-
      Partner JWT authentication: exchange a JWT for an access token, or launch
      a user into the app.
  - name: KYC
    description: >-
      Submit a customer's verification data, documents and questionnaire
      answers, import a verification they already passed elsewhere, and check
      where their KYC stands.
  - name: KYB
    description: Check where a business organization's KYB stands.
  - name: Lookup
    description: >-
      Public reference data: exchange rates, stablebonds, bond costs, country
      codes.
  - name: Organizations
    description: >-
      Your organization, your default partner fee, and the customer
      organizations you create.
  - name: Members
    description: >-
      The people who belong to a customer business organization and complete its
      KYB.
  - name: Statements
    description: >-
      Monthly revenue share statements for closed months, as a list or as a CSV
      or PDF download.
paths:
  /organization/{organizationId}/verification/documents:
    post:
      tags:
        - KYC
      summary: Upload verification documents
      description: >-
        Upload the customer's documents as `multipart/form-data`. Send at least
        one of `id_front`, `id_back`, `proof_of_address` or `tax_document`.


        **Submit the customer's personal data first.** Until [`POST
        /organization/{organizationId}/verification`](/v2/api-reference/kyc/submit-verification-data)
        has run the customer has no stages to upload against, so this answers
        `409`.


        **Answers `202`, not `200`.** We read and check every part before we
        answer, and send the upload to the verification provider after. Watch
        [`GET
        /organization/{organizationId}/kyc?requirements=true`](/v2/api-reference/kyc/get-kyc-status)
        for the requirement to go satisfied.


        **Upload what the current stage asks for.** Send a document once its
        requirement is listed. The exception is `proof_of_address`: you may send
        it with the identity document, before its own stage, as long as the
        identity stage has not been submitted yet. After that, wait for
        `proofOfAddress` to be listed. See [Requirements unlock in
        stages](/v2/guides/onboarding#requirements-unlock-in-stages).
      operationId: v2UploadVerificationDocuments
      parameters:
        - $ref: '#/components/parameters/OrganizationId'
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                id_front:
                  type: string
                  format: binary
                  description: >-
                    Front of the identity document, or its only side. JPEG, PNG
                    or PDF, up to 10 MB. At least one of `id_front`, `id_back`,
                    `proof_of_address` or `tax_document` must be sent.
                id_back:
                  type: string
                  format: binary
                  description: >-
                    Back of the identity document, where it has two sides. JPEG,
                    PNG or PDF, up to 10 MB. Required whenever `id_type` is
                    `id_card` or `drivers_license`, and refused for `passport`,
                    which is single-sided. Both sides go in the same request:
                    sending this without `id_front` is a 400, so a back cannot
                    be added to an earlier upload on its own.
                id_type:
                  type: string
                  description: >-
                    Which identity document the `id_*` parts are. Required
                    whenever one is sent. Case-sensitive: send the value exactly
                    as listed.
                  enum:
                    - ID_CARD
                    - PASSPORT
                    - DRIVERS
                proof_of_address:
                  type: string
                  format: binary
                  description: >-
                    A document evidencing the customer's address. JPEG, PNG or
                    PDF, up to 10 MB. Only accepted once the proof-of-address
                    requirement is outstanding: sent earlier it is accepted with
                    a 202 and then dropped, leaving the requirement outstanding.
                proof_of_address_type:
                  type: string
                  description: >-
                    Which kind of address document it is. Case-sensitive: send
                    the value exactly as listed.
                  default: UTILITY_BILL
                  enum:
                    - UTILITY_BILL
                    - BANK_STATEMENT
                    - TAX_BILL
                    - EMPLOYMENT_CERTIFICATE
                    - PROPERTY_DEED
                    - INVOICE
                tax_document:
                  type: string
                  format: binary
                  description: >-
                    A tax document, where the customer's country requires one;
                    in Mexico, the Constancia de Situación Fiscal. JPEG, PNG or
                    PDF, up to 10 MB. Not recorded for a customer whose
                    verification does not collect one. See [Country-specific
                    requirements](/v2/guides/onboarding#country-specific-requirements).
                country:
                  type: string
                  description: >-
                    Issuing country of these documents, as an ISO 3166-1 alpha-3
                    code. Only needed when the customer's profile has no country
                    yet.
                  example: MEX
            encoding:
              id_front:
                contentType: image/jpeg, image/png, application/pdf
              id_back:
                contentType: image/jpeg, image/png, application/pdf
              proof_of_address:
                contentType: image/jpeg, image/png, application/pdf
              tax_document:
                contentType: image/jpeg, image/png, application/pdf
      responses:
        '202':
          description: >-
            Accepted and being applied. The customer's current verification
            status is returned.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VerificationStatusResponse'
        '400':
          description: >-
            `invalid-request`: validation failed. An unrecognized `id_type` or
            `proof_of_address_type` is refused with the valid values listed.
            Otherwise `detail` names the first problem: a two-sided `id_type`
            without `id_back`, `id_back` without `id_front`, `id_back` for a
            single-sided `id_type`, a missing `id_type` alongside an `id_*`
            part, an unsupported content type, an empty or oversized file, an
            unrecognized `country`, or a body that is not valid
            `multipart/form-data`. Also returned for a business organization.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/OrganizationNotFound'
        '409':
          description: >-
            `conflict`, in one of three cases. Nothing has been submitted for
            this customer yet, so submit their personal data first. Or their
            personal data landed but they have not been routed to their
            country's requirements yet; `kycUpdated` fires when routing
            completes, or watch `GET
            /organization/{organizationId}/kyc?requirements=true` for the
            requirements list to appear. Or their verification is already
            approved or denied and cannot be modified.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '500':
          $ref: '#/components/responses/InternalError'
components:
  parameters:
    OrganizationId:
      name: organizationId
      in: path
      required: true
      description: >-
        The organization this call acts for: your API key's organization or one
        of its customer organizations. Any other id returns `404` `not-found`.
      schema:
        type: string
        format: uuid
  schemas:
    VerificationStatusResponse:
      type: object
      description: >-
        Where the customer's verification stands after a write. `status` is the
        same value `GET /organization/{organizationId}/kyc` reports.
      required:
        - organizationId
        - status
      properties:
        organizationId:
          type: string
          format: uuid
        status:
          $ref: '#/components/schemas/VerificationStatus'
      example:
        organizationId: a1b2c3d4-e5f6-7890-abcd-ef1234567890
        status: inProgress
    Problem:
      type: object
      description: >-
        RFC 9457 problem details. Every v2 error uses this body with content
        type `application/problem+json`. `errors` is present only on
        `validation-error`. `required` and `missing` are present only on
        `registration-info-required`.
      required:
        - type
        - title
        - status
        - detail
        - instance
      properties:
        type:
          type: string
          format: uri
          description: >-
            `https://docs.etherfuse.com/ramp/v2/errors/` followed by the problem
            slug, for example
            `https://docs.etherfuse.com/ramp/v2/errors/quote-expired`. Switch on
            this value.
          example: https://docs.etherfuse.com/ramp/v2/errors/quote-expired
        title:
          type: string
          description: Short summary of the problem type.
          example: Quote expired
        status:
          type: integer
          description: The HTTP status code.
          example: 400
        detail:
          type: string
          description: Human-readable explanation of this occurrence. Do not parse it.
          example: >-
            quote 5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b has expired or does not
            exist
        instance:
          type: string
          description: Unique identifier for this occurrence. Quote it to support.
          example: >-
            tag:etherfuse.com,2026-08-28:R2-10120/0b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d
        errors:
          type: array
          description: Present on `validation-error`. One entry per invalid field.
          items:
            $ref: '#/components/schemas/FieldViolation'
        required:
          type: array
          description: >-
            Present on `registration-info-required`. Every registration field
            the route requires, as JSON Pointers into the request, for example
            `#/registrationInfo/taxId`.
          items:
            type: string
        missing:
          type: array
          description: >-
            Present on `registration-info-required`. The required fields you
            must still send, as JSON Pointers into the request.
          items:
            type: string
    VerificationStatus:
      type: string
      enum:
        - notStarted
        - inProgress
        - submitted
        - approved
        - denied
      description: |-
        - `notStarted`: verification has not started.
        - `inProgress`: the customer started but has not submitted everything.
        - `submitted`: submitted and waiting for review.
        - `approved`: cleared.
        - `denied`: rejected, or a previous approval was revoked.
    FieldViolation:
      type: object
      required:
        - pointer
        - detail
      properties:
        pointer:
          type: string
          description: >-
            JSON Pointer to the field in the request, for example
            `#/accountDetails/clabe`.
          example: '#/accountDetails/clabe'
        detail:
          type: string
          description: What is wrong with the field.
          example: This field is required.
  responses:
    Unauthorized:
      description: >-
        `unauthorized`: the `Authorization` header is missing, not ASCII, or
        does not hold a valid API key.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    OrganizationNotFound:
      description: '`not-found`: your API key cannot act for this organization.'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    InternalError:
      description: >-
        `internal-error`: an unexpected error on our side. Retry with backoff,
        and quote `instance` to support if it persists.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: Authorization
      description: API key sent in the Authorization header, with no `Bearer` prefix.

````

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