> ## 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.

# Create a Payment from a Request

> Send the `reference` from `request-payload` and the ids it asked for. The
amount, the currency and the fee come off the reference — this call takes
none of them, and a body carrying `amount` or `currency` is refused with
`field_not_allowed`.

What is checked, in order:

- the reference is yours, unused and not past `expires_at`
  (`payment_request_expired`, `payment_request_consumed`);
- every field the request-payload marked required is present and nothing
  outside its `fields` was sent (`payload_incomplete`, `field_not_allowed`);
- the objects you named carry what `requirements` listed
  (`payload_incomplete` — the response repeats the `fields` entries that are
  still short, so you can fix the object and try again with the same
  reference);
- the terms still hold: if the route or our fee changed since the quote, the
  answer is `payment_request_stale` and you request a new payload.

Then the payment is created and, unless it is held for review, sent through.
A `bank` payout to a payee may be carried by a route that holds every payment
for review before it is submitted; such a payment answers `pending_review`.
That route pays payees only, never the user's own bank: a reference pinned
to it and spent on `bank_account_id` is `payment_request_stale`, and a
payload asked with `bank_account_id` named is never pinned to it.
The response is the payment, kept to what you need: `payment_id`, the
`reference`, `status`, the movement and its `payment_type` (`send` or
`transfer`, derived by us), `amount`, `currency`, our `fee` (billed on the
invoice, never taken out of the amount), the `user_id`, the source and
destination ids by the movement's own names, and — for a split —
`destinations`. Ids that do not apply to the movement are not sent.
`GET /v1/platform/payments/{payment_id}` still returns the fuller legacy
shape.

`destinations[]` — only when the request-payload reported
`destinations_supported` — credits several wallets from one payment; the leg
amounts must add up exactly to the amount on the reference, and it replaces
`destination_wallet_id`.

A card charged into a card-acquiring account may first need the cardholder to
authenticate: the answer is then a 422 `card_verification_required` carrying
`three_ds_url`, and the payment is created for the same reference once they
pass.

Supply a unique `idempotency_key` — a replay returns the payment as it stands
now. A reference creates at most one payment: using it again with another key
answers `payment_request_consumed` with the `payment_id`.



## OpenAPI

````yaml POST /v1/platform/payments/create-transaction
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: Redirect URLs
  - 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: Accounting
  - name: embed-tokens
paths:
  /v1/platform/payments/create-transaction:
    post:
      tags:
        - payments
      summary: Create the payment a request-payload described
      description: >-
        Send the `reference` from `request-payload` and the ids it asked for.
        The

        amount, the currency and the fee come off the reference — this call
        takes

        none of them, and a body carrying `amount` or `currency` is refused with

        `field_not_allowed`.


        What is checked, in order:


        - the reference is yours, unused and not past `expires_at`
          (`payment_request_expired`, `payment_request_consumed`);
        - every field the request-payload marked required is present and nothing
          outside its `fields` was sent (`payload_incomplete`, `field_not_allowed`);
        - the objects you named carry what `requirements` listed
          (`payload_incomplete` — the response repeats the `fields` entries that are
          still short, so you can fix the object and try again with the same
          reference);
        - the terms still hold: if the route or our fee changed since the quote,
        the
          answer is `payment_request_stale` and you request a new payload.

        Then the payment is created and, unless it is held for review, sent
        through.

        A `bank` payout to a payee may be carried by a route that holds every
        payment

        for review before it is submitted; such a payment answers
        `pending_review`.

        That route pays payees only, never the user's own bank: a reference
        pinned

        to it and spent on `bank_account_id` is `payment_request_stale`, and a

        payload asked with `bank_account_id` named is never pinned to it.

        The response is the payment, kept to what you need: `payment_id`, the

        `reference`, `status`, the movement and its `payment_type` (`send` or

        `transfer`, derived by us), `amount`, `currency`, our `fee` (billed on
        the

        invoice, never taken out of the amount), the `user_id`, the source and

        destination ids by the movement's own names, and — for a split —

        `destinations`. Ids that do not apply to the movement are not sent.

        `GET /v1/platform/payments/{payment_id}` still returns the fuller legacy

        shape.


        `destinations[]` — only when the request-payload reported

        `destinations_supported` — credits several wallets from one payment; the
        leg

        amounts must add up exactly to the amount on the reference, and it
        replaces

        `destination_wallet_id`.


        A card charged into a card-acquiring account may first need the
        cardholder to

        authenticate: the answer is then a 422 `card_verification_required`
        carrying

        `three_ds_url`, and the payment is created for the same reference once
        they

        pass.


        Supply a unique `idempotency_key` — a replay returns the payment as it
        stands

        now. A reference creates at most one payment: using it again with
        another key

        answers `payment_request_consumed` with the `payment_id`.
      operationId: create_payment_transaction_v1_platform_payments_create_transaction_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PaymentTransactionCreate'
        required: true
      responses:
        '201':
          description: Payment created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CommonResponse'
              example:
                status_code: 201
                data:
                  payment_id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
                  reference: 3f9c1b2a-9d84-4e15-8c26-0b7a5d3e1f90
                  status: processing
                  source_type: wallet
                  destination_type: bank
                  payment_type: send
                  amount: 250
                  currency: USD
                  fee: 3
                  user_id: 00000000-0000-0000-0000-000000000001
                  wallet_id: 11111111-1111-1111-1111-111111111111
                  payee_destination_id: 22222222-2222-2222-2222-222222222222
                  created_at: '2026-09-11T10:05:00Z'
                query_generated_time: 1712847600000
        '409':
          description: >-
            payment_request_expired, payment_request_consumed,
            payment_request_stale
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CodedErrorResponse'
              examples:
                payment_request_expired:
                  summary: payment_request_expired (error_code 1108)
                  value:
                    status_code: 409
                    data:
                      detail: >-
                        This payment request has expired. Request a new payload
                        and use the new reference.
                      code: payment_request_expired
                      error_code: 1108
                    query_generated_time: 1750000000000
                payment_request_consumed:
                  summary: payment_request_consumed (error_code 1109)
                  value:
                    status_code: 409
                    data:
                      detail: >-
                        This reference has already been used to create a
                        payment. Request a new payload for another payment.
                      code: payment_request_consumed
                      error_code: 1109
                    query_generated_time: 1750000000000
                payment_request_stale:
                  summary: payment_request_stale (error_code 1110)
                  value:
                    status_code: 409
                    data:
                      detail: >-
                        The terms of this payment request are no longer current.
                        Request a new payload and retry with the new reference.
                      code: payment_request_stale
                      error_code: 1110
                    query_generated_time: 1750000000000
        '422':
          description: payload_incomplete, field_not_allowed, destinations_not_supported
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CodedErrorResponse'
              examples:
                payload_incomplete:
                  summary: payload_incomplete (error_code 1111)
                  value:
                    status_code: 422
                    data:
                      detail: >-
                        The payload does not carry everything this payment
                        needs. See fields for what is missing.
                      code: payload_incomplete
                      error_code: 1111
                    query_generated_time: 1750000000000
                field_not_allowed:
                  summary: field_not_allowed (error_code 1112)
                  value:
                    status_code: 422
                    data:
                      detail: The body carries a field this payment does not take.
                      code: field_not_allowed
                      error_code: 1112
                    query_generated_time: 1750000000000
                destinations_not_supported:
                  summary: destinations_not_supported (error_code 1113)
                  value:
                    status_code: 422
                    data:
                      detail: >-
                        destinations can only be given when the destination is a
                        wallet and the payment request reported
                        destinations_supported.
                      code: destinations_not_supported
                      error_code: 1113
                    query_generated_time: 1750000000000
        '503':
          description: payment_request_unavailable
          content:
            application/json:
              examples:
                payment_request_unavailable:
                  summary: payment_request_unavailable (error_code 1107)
                  value:
                    status_code: 503
                    data:
                      detail: >-
                        A payment request cannot be prepared for this movement
                        at the moment. Please try again later or contact
                        support.
                      code: payment_request_unavailable
                      error_code: 1107
                    query_generated_time: 1750000000000
              schema:
                $ref: '#/components/schemas/CodedErrorResponse'
      security:
        - _AuthenticatedBearer: []
components:
  schemas:
    PaymentTransactionCreate:
      properties:
        reference:
          type: string
          format: uuid
          title: Reference
          description: The reference `request-payload` returned.
        idempotency_key:
          type: string
          maxLength: 120
          minLength: 1
          title: Idempotency Key
          description: >-
            A unique value you pick for this payment. If the same request
            reaches us twice, the payment happens once.
        wallet_id:
          anyOf:
            - type: string
              format: uuid
            - type: 'null'
          title: Wallet Id
          description: The wallet to debit.
        destination_wallet_id:
          anyOf:
            - type: string
              format: uuid
            - type: 'null'
          title: Destination Wallet Id
          description: The wallet to credit.
        bank_account_id:
          anyOf:
            - type: string
              format: uuid
            - type: 'null'
          title: Bank Account Id
          description: >-
            The user's linked bank account — the source of a deposit, or the
            user's own bank on a withdrawal.
        card_id:
          anyOf:
            - type: string
              format: uuid
            - type: 'null'
          title: Card Id
          description: The user's saved card.
        vba_id:
          anyOf:
            - type: string
              format: uuid
            - type: 'null'
          title: Vba Id
          description: The user's virtual bank account to move funds from.
        payee_destination_id:
          anyOf:
            - type: string
              format: uuid
            - type: 'null'
          title: Payee Destination Id
          description: The payee's bank destination to pay.
        payee_address_id:
          anyOf:
            - type: string
              format: uuid
            - type: 'null'
          title: Payee Address Id
          description: >-
            The payee's address in the destination country, when the
            request-payload marked it required — a payout abroad, or a `bank`
            payout whose route asks for it. Sent only together with
            `payee_destination_id`.
        card_acquiring_id:
          anyOf:
            - type: string
              format: uuid
            - type: 'null'
          title: Card Acquiring Id
          description: >-
            The card-acquiring account to deposit into; defaults to the oldest
            approved one.
        destinations:
          anyOf:
            - items:
                $ref: '#/components/schemas/PaymentDestinationCreate'
              type: array
            - type: 'null'
          title: Destinations
          description: >-
            Credit several wallets from this one payment. Only when the
            request-payload reported `destinations_supported`; replaces
            `destination_wallet_id`; the legs must add up exactly to the amount
            on the reference.
        user_id:
          anyOf:
            - type: string
              format: uuid
            - type: 'null'
          title: User Id
          description: >-
            Safety cross-check against the wallet owner — and, for a card
            charged into a card-acquiring account, the payer being charged
            (required there).
        metadata:
          additionalProperties: true
          type: object
          title: Metadata
          description: Your own key-value notes, stored with the payment.
        payment_category:
          anyOf:
            - type: integer
              exclusiveMinimum: 0
            - type: 'null'
          title: Payment Category
          description: >-
            Optional. The payment category `code` to tag this payment with,
            recording what the payment was for. Omit it and the payment is
            created exactly as before, untagged. If you do send one it must be a
            code your platform can currently use, otherwise the request is
            rejected and no money moves. Fetch the codes from `GET
            /v1/platform/catalog/payment-categories`. Codes are issued
            separately in test and live, so read the list in each mode — the
            same number does not mean the same category across them.
          examples:
            - 1
        notify_recipient:
          type: boolean
          title: Notify Recipient
          description: Ask us to notify the recipient (payee destinations).
          default: false
        from_hold:
          type: boolean
          title: From Hold
          description: Spend from the wallet's held funds (wallet sources).
          default: false
      additionalProperties: true
      type: object
      required:
        - reference
        - idempotency_key
      title: PaymentTransactionCreate
      description: >-
        Request body for ``POST /v1/platform/payments/create-transaction``.


        ``extra="allow"`` is deliberate: a body carrying `amount`, `currency`,

        `product_id` or any other field this call does not take is refused by
        the

        service with a coded ``field_not_allowed`` that says the value comes
        from the

        request-payload — ``extra="forbid"`` would turn that into a generic 422

        before the route ran.
    CommonResponse:
      properties:
        status_code:
          type: integer
          title: Status Code
          description: HTTP status code for the response.
        data:
          title: Data
          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
      description: |-
        Standard response wrapper for single-object responses and errors.

        Generic over the payload type. A route that declares
        ``CommonResponse[SomeModel]`` gets the real ``data`` schema rendered in
        OpenAPI/Swagger; a bare ``CommonResponse`` leaves ``data`` untyped.
    CodedErrorResponse:
      properties:
        status_code:
          type: integer
          title: Status Code
          description: HTTP status code for the response.
        data:
          $ref: '#/components/schemas/CodedErrorBody'
          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: CodedErrorResponse
      description: Standard envelope wrapping a :class:`CodedErrorBody`.
    PaymentDestinationCreate:
      properties:
        wallet_id:
          type: string
          format: uuid
          title: Wallet Id
          description: >-
            The wallet this leg credits. Any wallet under your platform in the
            payment's currency; each wallet at most once.
        amount:
          anyOf:
            - type: number
              exclusiveMinimum: 0
            - type: string
              pattern: ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$
          title: Amount
          description: >-
            What this wallet receives, major units, at most 2 decimal places.
            The legs must add up exactly to the amount on the reference.
        role:
          type: string
          enum:
            - beneficiary
            - fee
          title: Role
          description: >-
            Display label for reporting — `beneficiary` (default) or `fee` (your
            own margin). The money moves identically either way.
          default: beneficiary
      additionalProperties: false
      type: object
      required:
        - wallet_id
        - amount
      title: PaymentDestinationCreate
      description: One wallet credited from a payment whose destination is a wallet.
    CodedErrorBody:
      properties:
        detail:
          type: string
          title: Detail
          description: Human-readable error message.
        code:
          type: string
          title: Code
          description: Stable string error code — the canonical value to branch on.
        error_code:
          type: integer
          title: Error Code
          description: >-
            Numeric custom error code from the Finogate registry. Unique per
            condition and stable forever.
      type: object
      required:
        - detail
        - code
        - error_code
      title: CodedErrorBody
      description: >-
        The ``data`` payload of a coded-error response.


        Condition-specific extras (e.g. ``remaining_time``) may also appear;
        only

        the always-present fields are typed here.
  securitySchemes:
    _AuthenticatedBearer:
      type: oauth2
      flows:
        password:
          scopes: {}
          tokenUrl: /v1/platform/auth/token

````