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

# Onboard a Merchant for Card Processing

> Onboard a business for card processing in one call.

This is the combined form of several separate calls — create the user, record their identity check, record the business check, submit the card-processing application, and optionally attach its underwriting packet. Use it when you already hold everything needed to onboard the merchant.

The request is `multipart/form-data`. The structured half goes in the **`payload`** form field as JSON text; the supporting documents are separate binary file parts.

**Identity — supply exactly one of these. Sending both is rejected.**

- `inquiry_id` — an identity-verification inquiry id you already hold for this individual. The verified details are pulled from the verification provider. The inquiry must belong to the same environment you are calling in; one created in sandbox cannot be read in production, or vice versa.
- `kyc` — the identity details keyed in directly, when no inquiry exists. **Every field is required**, because this arm must carry everything the inquiry arm would have returned from the provider: `first_name`, `last_name`, `email`, `dob` (`YYYY-MM-DD`), `phone_country_code`, `phone_no`, `ssn`, `address`, `city`, `state`, `zip`, `country` (ISO alpha-2), `id_type`, `id_no`, and the image links `selfie`, `id_front_img`, `id_back_img`. If a value does not exist for this individual, use `inquiry_id` instead.

**Business — `kyb` is required.** Same shape as `POST /v1/platform/users/kyb/start/{user_id}`, with one difference: `kyb.business_data.business_email` is **required** here. It is the merchant's email; there is no separate field to override it.

`kyb.business_data.website` is **required** here too — an application cannot be underwritten without the site the payments originate from.

`kyb.business_data.business_documents` must carry **2 to 5** links to the business-verification documents.

**Underwriting — `merchant_info` is required**, together with its document file parts:

- `merchant_info.average_ticket_minor` — average transaction amount, minor units (cents).
- `merchant_info.monthly_volume_minor` — expected monthly processing volume, minor units.
- `merchant_info.max_ticket_minor` — maximum expected transaction amount, minor units. Cannot be lower than `average_ticket_minor`.
- **`voided_check`** file part — **required**.
- **`bank_statements`** file part — **required**, last 3 months, one file.
- **`processing_statements`** file part — optional; only applies when the business already processes with another provider.

There is no `merchant_info.website`: it is read from `kyb.business_data.website`, so one merchant states one site.

**File size limits**, per file:

- Uploaded supporting documents (`voided_check`, `bank_statements`, `processing_statements`) — **10 MB**.
- Linked identity images and business documents — **7 MB**.

**Links are downloaded and re-hosted, not just recorded.** Every document and identity-image link you send is fetched once while the request is being handled, stored on Finogate's own storage, and it is that stored copy which is kept against the verification record. Your original URL is not retained, so it can expire or rotate afterwards without affecting the record.

Because of that, links must actually be fetchable at the moment you call:

- `https://` only. Plain `http://` is rejected.
- The host must be publicly reachable. Private, loopback and link-local addresses are refused.
- The file must be a **PNG, JPG, JPEG or PDF** — the only types this endpoint accepts, for uploads and links alike. HEIC/HEIF are **not** supported, so convert iPhone photos before sending.
- An `s3://` URI already on Finogate storage is kept as-is and not re-fetched.

If any link cannot be fetched the whole call fails with `422` and nothing is created — a verification record is never approved against a document we could not retrieve. To upload files directly instead, use `POST /v1/platform/users/kyb/start/{user_id}`.

The merchant is created with a `Primary` USD wallet, the same as `POST /v1/platform/users`.

**Everything this call files goes to review.** One call replaces four requests; it does not replace the decision. The identity check, the business check and the card-processing application are all created awaiting review, exactly as the per-step endpoints leave them, and each is approved or declined by Finogate afterwards. The merchant cannot process cards, and no MID is issued, until the application is approved — which requires the identity and business checks to be approved first.

If your platform runs its own KYC/KYB programme, that identity and business review can be waived for you: Finogate then reads the verdict you already hold for the merchant instead of repeating the check, and approves both on your `APPROVED`. This is arranged with Finogate per platform and is off unless it has been set up for you; the card-processing application is still decided by Finogate either way. Contact support to have your programme assessed.

Poll the verification and card-processing endpoints for status, or subscribe to the `user_kyc.*`, `user_kyb.*` and `card_acquiring.application.*` webhooks.

**Repeat submissions for the same merchant email.** What happens depends on what that merchant already has:

- An application still **awaiting review** — rejected with `409`. Only one may be in flight at a time; wait for it to be approved or declined.
- A previously **approved** application for the **same business** (same legal name and EIN) — that application is returned unchanged and nothing is written, so retrying after a timeout cannot create a duplicate merchant.
- A previously **approved** application for a **different business** — a new business check and a new application are created. One email can hold several companies.

Declined and suspended applications never block a new submission.

The response is the three ids this call produced. The records themselves are read from the endpoints that own them — see the response schema.



## OpenAPI

````yaml POST /v1/platform/merchant-onboarding
openapi: 3.1.0
info:
  title: Finogate Platform API v1
  version: 0.1.0
servers:
  - url: https://api-sandbox.finogates.com
    description: Sandbox
  - url: https://api.finogates.com
    description: Production
security: []
tags:
  - name: auth
  - name: users
  - name: payees
  - name: verification
  - name: bank accounts
  - name: card processing
  - name: digital-assets
  - name: international
  - name: fees
  - name: onboarding
  - name: pending-applications
  - name: wallets
  - name: payments
  - name: document mailing
  - name: merchant onboarding
  - name: catalog
  - name: webhooks
  - name: screening
  - name: Platform - File Scanning
  - name: phone-numbers
  - name: sms
  - name: calls
  - name: listings
  - name: Card Transfers
  - name: embed-tokens
paths:
  /v1/platform/merchant-onboarding:
    post:
      tags:
        - merchant onboarding
      summary: Onboard a Merchant for Card Processing
      description: >-
        Onboard a business for card processing in one call.


        This is the combined form of several separate calls — create the user,
        record their identity check, record the business check, submit the
        card-processing application, and optionally attach its underwriting
        packet. Use it when you already hold everything needed to onboard the
        merchant.


        The request is `multipart/form-data`. The structured half goes in the
        **`payload`** form field as JSON text; the supporting documents are
        separate binary file parts.


        **Identity — supply exactly one of these. Sending both is rejected.**


        - `inquiry_id` — an identity-verification inquiry id you already hold
        for this individual. The verified details are pulled from the
        verification provider. The inquiry must belong to the same environment
        you are calling in; one created in sandbox cannot be read in production,
        or vice versa.

        - `kyc` — the identity details keyed in directly, when no inquiry
        exists. **Every field is required**, because this arm must carry
        everything the inquiry arm would have returned from the provider:
        `first_name`, `last_name`, `email`, `dob` (`YYYY-MM-DD`),
        `phone_country_code`, `phone_no`, `ssn`, `address`, `city`, `state`,
        `zip`, `country` (ISO alpha-2), `id_type`, `id_no`, and the image links
        `selfie`, `id_front_img`, `id_back_img`. If a value does not exist for
        this individual, use `inquiry_id` instead.


        **Business — `kyb` is required.** Same shape as `POST
        /v1/platform/users/kyb/start/{user_id}`, with one difference:
        `kyb.business_data.business_email` is **required** here. It is the
        merchant's email; there is no separate field to override it.


        `kyb.business_data.website` is **required** here too — an application
        cannot be underwritten without the site the payments originate from.


        `kyb.business_data.business_documents` must carry **2 to 5** links to
        the business-verification documents.


        **Underwriting — `merchant_info` is required**, together with its
        document file parts:


        - `merchant_info.average_ticket_minor` — average transaction amount,
        minor units (cents).

        - `merchant_info.monthly_volume_minor` — expected monthly processing
        volume, minor units.

        - `merchant_info.max_ticket_minor` — maximum expected transaction
        amount, minor units. Cannot be lower than `average_ticket_minor`.

        - **`voided_check`** file part — **required**.

        - **`bank_statements`** file part — **required**, last 3 months, one
        file.

        - **`processing_statements`** file part — optional; only applies when
        the business already processes with another provider.


        There is no `merchant_info.website`: it is read from
        `kyb.business_data.website`, so one merchant states one site.


        **File size limits**, per file:


        - Uploaded supporting documents (`voided_check`, `bank_statements`,
        `processing_statements`) — **10 MB**.

        - Linked identity images and business documents — **7 MB**.


        **Links are downloaded and re-hosted, not just recorded.** Every
        document and identity-image link you send is fetched once while the
        request is being handled, stored on Finogate's own storage, and it is
        that stored copy which is kept against the verification record. Your
        original URL is not retained, so it can expire or rotate afterwards
        without affecting the record.


        Because of that, links must actually be fetchable at the moment you
        call:


        - `https://` only. Plain `http://` is rejected.

        - The host must be publicly reachable. Private, loopback and link-local
        addresses are refused.

        - The file must be a **PNG, JPG, JPEG or PDF** — the only types this
        endpoint accepts, for uploads and links alike. HEIC/HEIF are **not**
        supported, so convert iPhone photos before sending.

        - An `s3://` URI already on Finogate storage is kept as-is and not
        re-fetched.


        If any link cannot be fetched the whole call fails with `422` and
        nothing is created — a verification record is never approved against a
        document we could not retrieve. To upload files directly instead, use
        `POST /v1/platform/users/kyb/start/{user_id}`.


        The merchant is created with a `Primary` USD wallet, the same as `POST
        /v1/platform/users`.


        **Everything this call files goes to review.** One call replaces four
        requests; it does not replace the decision. The identity check, the
        business check and the card-processing application are all created
        awaiting review, exactly as the per-step endpoints leave them, and each
        is approved or declined by Finogate afterwards. The merchant cannot
        process cards, and no MID is issued, until the application is approved —
        which requires the identity and business checks to be approved first.


        If your platform runs its own KYC/KYB programme, that identity and
        business review can be waived for you: Finogate then reads the verdict
        you already hold for the merchant instead of repeating the check, and
        approves both on your `APPROVED`. This is arranged with Finogate per
        platform and is off unless it has been set up for you; the
        card-processing application is still decided by Finogate either way.
        Contact support to have your programme assessed.


        Poll the verification and card-processing endpoints for status, or
        subscribe to the `user_kyc.*`, `user_kyb.*` and
        `card_acquiring.application.*` webhooks.


        **Repeat submissions for the same merchant email.** What happens depends
        on what that merchant already has:


        - An application still **awaiting review** — rejected with `409`. Only
        one may be in flight at a time; wait for it to be approved or declined.

        - A previously **approved** application for the **same business** (same
        legal name and EIN) — that application is returned unchanged and nothing
        is written, so retrying after a timeout cannot create a duplicate
        merchant.

        - A previously **approved** application for a **different business** — a
        new business check and a new application are created. One email can hold
        several companies.


        Declined and suspended applications never block a new submission.


        The response is the three ids this call produced. The records themselves
        are read from the endpoints that own them — see the response schema.
      operationId: onboard_merchant_v1_platform_merchant_onboarding_post
      requestBody:
        content:
          multipart/form-data:
            schema:
              $ref: >-
                #/components/schemas/Body_onboard_merchant_v1_platform_merchant_onboarding_post
        required: true
      responses:
        '201':
          description: The merchant was onboarded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CommonResponse_MerchantOnboardingRead_'
              example:
                status_code: 201
                data:
                  user_id: 228e4b03-6831-4b63-ad8e-2250d01f6d64
                  kyb_id: 69b336da-331c-4ddf-8ac5-0a0557c7f279
                  card_acquiring_id: 07f78e86-b3c6-4761-84ae-22176ca015c1
                query_generated_time: 1712847600000
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      security:
        - _AuthenticatedBearer: []
components:
  schemas:
    Body_onboard_merchant_v1_platform_merchant_onboarding_post:
      properties:
        payload:
          type: string
          title: Payload
          description: >-
            The onboarding details, sent as JSON text. See the endpoint
            description for the object's shape.
        voided_check:
          type: string
          format: binary
          title: Voided Check
          description: Voided check for the account settlements should land in.
        bank_statements:
          type: string
          format: binary
          title: Bank Statements
          description: Last 3 months of business bank statements, one file.
        processing_statements:
          anyOf:
            - type: string
              format: binary
            - type: 'null'
          title: Processing Statements
          description: >-
            Last 3 months of merchant processing statements. Optional — it only
            applies when the business already processes with another provider.
      type: object
      required:
        - payload
        - voided_check
        - bank_statements
      title: Body_onboard_merchant_v1_platform_merchant_onboarding_post
    CommonResponse_MerchantOnboardingRead_:
      properties:
        status_code:
          type: integer
          title: Status Code
          description: HTTP status code for the response.
        data:
          $ref: '#/components/schemas/MerchantOnboardingRead'
          description: Payload or error details.
        query_generated_time:
          type: integer
          title: Query Generated Time
          description: >-
            UTC timestamp (milliseconds since epoch) when response was
            generated.
      type: object
      required:
        - status_code
        - data
        - query_generated_time
      title: CommonResponse[MerchantOnboardingRead]
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    MerchantOnboardingRead:
      properties:
        user_id:
          type: string
          format: uuid
          title: User Id
          description: The merchant's public id.
        kyb_id:
          type: string
          format: uuid
          title: Kyb Id
          description: Public id of the business (KYB) record.
        card_acquiring_id:
          type: string
          format: uuid
          title: Card Acquiring Id
          description: >-
            Public id of the card-acquiring application. Use it against `GET
            /v1/platform/card-processing/{application_id}`.
      type: object
      required:
        - user_id
        - kyb_id
        - card_acquiring_id
      title: MerchantOnboardingRead
      description: >-
        The three ids a call produced — handles, not records.


        Returned by both endpoints that end in a filed application: the one-shot

        ``POST /v1/platform/merchant-onboarding``, which creates all three
        records,

        and ``POST /v1/platform/card-processing``, which files an application

        against a user and business check that already exist and so reports back

        the ids it was given alongside the one it created. Same outcome, same

        shape — an integrator handling one does not need a second reader for the

        other.


        Nothing is approved by either. None of the records' detail is echoed
        back:

        it is data the caller already sent, and re-emitting it would spread

        personal and business information across another response body and
        another

        log line for no gain.


        Nothing is lost — each id is the key to the endpoint that owns that
        record,

        and that is where the current review status is read from:


        * ``card_acquiring_id`` -> ``GET /v1/platform/card-processing/{id}``

        * ``kyb_id`` -> ``GET /v1/platform/card-processing/kybs/{kyb_id}``

        * ``user_id`` -> ``GET /v1/platform/users/verification/{user_id}``
          and ``GET /v1/platform/users/kyb-records/{user_id}``
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
      type: object
      required:
        - loc
        - msg
        - type
      title: ValidationError
  securitySchemes:
    _AuthenticatedBearer:
      type: oauth2
      flows:
        password:
          scopes: {}
          tokenUrl: /v1/platform/auth/token

````