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

# Create On-Ramp

Creates an on-ramp transaction on behalf of a **verified** user. This converts fiat to crypto — the user deposits fiat via bank transfer and receives crypto at the specified wallet address. The response returns the bank account details for the fiat deposit.

<Note>
  For staging transaction testing, use the [Mock Testing Guide](/reference/transactionpartnerv2controller_getmocktestingguide).
</Note>

***

## Idempotency

Retry safely without creating duplicate transactions: pass an optional **`Idempotency-Key`** header (UUIDv4). A retry with the same key and body replays the original response. See the [Idempotency Guide](/docs/idempotency) for the full contract.

```shell theme={null}
curl --request POST \
  --url https://staging-api.capa.fi/api/partner/v2/on-ramp \
  --header 'Content-Type: application/json' \
  --header 'partner-api-key: <partner-api-key>' \
  --header 'Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000' \
  --data '...'
```

***

## Field Relationships

* Provide `quoteId` **OR** (`fiatCurrency` + `blockchainSymbol` + `tokenSymbol`). When a quote is used, currency/token fields are inherited from the quote.
* Provide either `fiatAmount` or `cryptoAmount`, not both.
* Provide either `destinationWalletAddress` (inline) or `walletAddressId` (reference to a saved wallet).

***

## Integration Flow

<Steps>
  <Step title="Create a user">
    [POST /api/partner/v2/users](/reference/userpartnercontrollerv2_createuser)
  </Step>

  <Step title="Complete KYC verification">
    [POST /api/partner/v2/users/{userId}/kyc/verification-link](/reference/userpartnercontrollerv2_createverificationlink)
  </Step>

  <Step title="Get a quote (optional)">
    [POST /api/partner/v2/quotes](/reference/quotepartnerv2controller_createpartnerquote) — locks the exchange rate
  </Step>

  <Step title="Create on-ramp transaction">
    `POST /api/partner/v2/on-ramp` (this endpoint) — returns bank account details for the fiat deposit
  </Step>

  <Step title="User deposits fiat">
    The user sends fiat to the bank account returned in the `bankAccount` response field.
  </Step>
</Steps>

***

## Important Notes

* **User must be KYC-verified** before creating transactions.
* **Wallet type must match blockchain**: An EVM wallet cannot be used on a Solana chain, and vice versa.
* **Amount limits**: Fiat and crypto amounts must fall within the min/max thresholds defined in your partner agreement.

***

## Use Cases

* **Buy Crypto**: Enable users to purchase cryptocurrency using fiat deposited via bank transfer.
* **B2C Integration**: Let individual users on-ramp from within your app.
* **Automated Purchases**: Programmatically initiate fiat-to-crypto conversions for your users.

***

## Error Codes

### Common Errors

| HTTP Status | Code                   | Message                            |
| ----------- | ---------------------- | ---------------------------------- |
| 401         | `UNAUTHORIZED`         | "API Key is missing"               |
| 401         | `UNAUTHORIZED`         | "Invalid API Key format"           |
| 401         | `UNAUTHORIZED`         | "Invalid API Key"                  |
| 403         | `INVALID_PARTNER_FLOW` | "The partner has an invalid flow." |

### Verified User Errors

| HTTP Status | Code                      | Message                                                                                         |
| ----------- | ------------------------- | ----------------------------------------------------------------------------------------------- |
| 400         | `REQUIRED_USER_ID_ERROR`  | "This endpoint requires a user id to be provided"                                               |
| 403         | `USER_NOT_VERIFIED_ERROR` | "User is not allowed to perform the operations because has not completed the KYC verification." |

### Endpoint-Specific Errors

| HTTP Status | Code                                   | Message                                                                                                                          |
| ----------- | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| 400         | `INVALID_USER_INPUT_ERROR`             | "Invalid User Input"                                                                                                             |
| 400         | `BAD_REQUEST`                          | "address {address} must be a valid {vmType} address"                                                                             |
| 400         | `BAD_REQUEST`                          | "Either quoteId or fiatCurrency, blockchainSymbol, tokenSymbol, and at least one of fiatAmount or cryptoAmount must be provided" |
| 400         | `BAD_REQUEST`                          | "Fiat currency is disabled or does not exist"                                                                                    |
| 400         | `BAD_REQUEST`                          | "This blockchain and token combination is disabled or does not exist"                                                            |
| 400         | `QUOTE_EXPIRED`                        | "Quote has expired"                                                                                                              |
| 400         | `BAD_REQUEST`                          | "Quote is not valid for ON\_RAMP"                                                                                                |
| 400         | `INVALID_TOKEN_OPERATION_ERROR`        | "Token {symbol} cannot be operated as OTC, only stable coins are allowed"                                                        |
| 400         | `BAD_REQUEST`                          | "Either walletAddressId or destinationWalletAddress must be provided"                                                            |
| 400         | `BAD_REQUEST`                          | "Cannot create transaction: No supported banks configured for user with id: {userId}"                                            |
| 400         | `INVALID_FIAT_AMOUNT_ERROR`            | "Fiat amount {amount} is outside of the allowed range for ON\_RAMP. Should be between {min} and {max}"                           |
| 400         | `INVALID_TOKEN_AMOUNT_ERROR`           | "Token amount {amount} is outside of the allowed range for ON\_RAMP. Should be between {min} and {max}"                          |
| 403         | `RECEIVER_CANNOT_INITIATE_TRANSACTION` | "Receiver accounts cannot initiate transactions directly."                                                                       |


## OpenAPI

````yaml reference/openapi/OnRampPartnerV2Controller_createPartnerOnRamp.json POST /api/partner/v2/on-ramp
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://staging-api.capa.fi
  - url: https://production-api.capa.fi
security: []
paths:
  /api/partner/v2/on-ramp:
    post:
      tags:
        - on-ramp
      operationId: OnRampPartnerV2Controller_createPartnerOnRamp
      parameters:
        - name: Idempotency-Key
          in: header
          description: >-
            Optional. Unique key (UUIDv4 recommended) to safely retry this
            request without creating a duplicate transaction. A retry with the
            same key and body replays the original response. See
            /docs/idempotency.
          required: false
          schema:
            type: string
            minLength: 16
            maxLength: 128
            example: 550e8400-e29b-41d4-a716-446655440000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                quoteId:
                  type: string
                  description: Identifier for the quote to be used for the transaction.
                userId:
                  type: string
                  description: Identifier for the user
                  example: 8374f327-38bd-4b0b-b8a7-2524599eb903
                fiatAmount:
                  type: number
                  description: Amount of fiat currency to be converted to crypto currency.
                cryptoAmount:
                  type: number
                  description: Amount of cryptocurrency to be received in conversion.
                destinationWalletAddress:
                  type: string
                  description: Wallet address of the user making the transaction.
                  example: '0x4d2f3d8f83b6f2f8e0f3f4f3f3f3f3f3f3f3f3f3'
                fiatCurrency:
                  description: Identifier for the fiat currency which the user will rec.
                  example: MXN
                  enum:
                    - MXN
                    - DOP
                    - USD
                    - EUR
                  type: string
                blockchainSymbol:
                  description: >-
                    Identifier for the blockchain to token from which the
                    conversion will be made.

                    BSC is only available for transactions over 50,000 MXN.
                  example: POL
                  enum:
                    - POL
                    - SOL
                    - ETH
                    - BSC
                  type: string
                tokenSymbol:
                  description: >-
                    Identifier for the token from which the conversion will be
                    made.
                  example: USDC
                  enum:
                    - USDC
                    - USDT
                  type: string
                premiumSpread:
                  type: number
                  description: Spread percentage to be applied to the exchange rate
              required:
                - userId
                - destinationWalletAddress
              x-readme-ref-name: CreatePartnerOnRampTransactionV2RequestBody
      responses:
        '201':
          description: >-
            On-ramp transaction created successfully. Returns the transaction
            details, including the bank account the user must fund and the
            current status.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        description: Transaction identifier
                        example: 63f51f11-6869-47b0-a109-ddb50ef20efb
                      userId:
                        type: string
                        description: User identifier
                        example: 8374f327-38bd-4b0b-b8a7-2524599eb903
                      status:
                        type: string
                        description: Transaction status
                        example: PENDING_PAYMENT
                      cryptoAmount:
                        type: number
                        description: Amount of crypto currency involved in the transaction
                        example: 2500
                      fiatAmount:
                        type: number
                        description: Amount of fiat currency involved in the transaction
                        example: 50000
                      crossFiatAmount:
                        type: number
                      exchangeRate:
                        type: number
                        description: Exchange rate used for the transaction
                        example: 19.53964594161554
                      tokenSymbol:
                        description: Token symbol
                        example: USDC
                        enum:
                          - USDC
                          - USDT
                        type: string
                      blockchainSymbol:
                        description: Blockchain symbol
                        example: POL
                        enum:
                          - POL
                          - SOL
                          - ETH
                          - BSC
                        type: string
                      fiatCurrency:
                        description: Fiat currency symbol
                        example: MXN
                        enum:
                          - MXN
                          - DOP
                          - USD
                          - EUR
                        type: string
                      premiumSpread:
                        type: number
                        description: >-
                          Premium spread applied to the transaction (0 if not
                          provided)
                        example: 0.01
                      forwardingDays:
                        type: number
                        description: >-
                          Number of T+N forwarding days for settlement (0-4).
                          Only for MXN OTC transactions.
                        example: 2
                      effectiveForwardingDays:
                        type: number
                        description: >-
                          Effective forwarding days for settlement (may differ
                          from requested due to holidays/weekends).
                        example: 4
                      forwardingSettlementDate:
                        format: date-time
                        type: string
                        description: >-
                          Calculated settlement date based on effective
                          forwarding days offset.
                        example: '2026-03-14T03:25:27.495Z'
                      createdAt:
                        type: string
                        description: Transaction creation date
                        example: '2025-05-14T10:00:00Z'
                      completedAt:
                        type: string
                        nullable: true
                        description: Transaction completion date (null if not completed)
                      destinationWalletAddress:
                        type: string
                        description: Destination wallet address for the transaction
                        example: '0x7796d4f304bd84171ee6730ad0f69c07a47e786d'
                      bankAccount:
                        description: Bank account information
                        allOf:
                          - type: object
                            properties:
                              country:
                                type: string
                                description: The country of the bank account
                                example: MX
                              accountIdentifier:
                                type: string
                                description: >-
                                  The account identifier for the bank account
                                  (CLABE in MX, account number elsewhere)
                                example: '014680260346007120'
                              bankName:
                                type: string
                                description: The name of the bank
                                example: Santander
                              accountType:
                                type: string
                                description: The type of the account
                                example: SAVINGS
                              isVerified:
                                type: boolean
                                description: Whether the account is verified
                                example: true
                              documentIdentifier:
                                type: string
                                description: >-
                                  The document identifier used for verification
                                  (e.g. national tax / ID number)
                                example: 123abc
                              documentType:
                                type: string
                                description: >-
                                  Type of the document bound to the account
                                  (country specific)
                                example: RNC
                              iban:
                                type: string
                                description: >-
                                  International Bank Account Number (SEPA / EU
                                  accounts)
                                example: DE89370400440532013000
                              bic:
                                type: string
                                description: >-
                                  Bank Identifier Code (SWIFT BIC) for SEPA / EU
                                  accounts
                                example: DEUTDEFF
                              routingNumber:
                                type: string
                                description: ABA routing number (US only, 9 digits)
                                example: '021000021'
                            required:
                              - country
                              - accountIdentifier
                              - isVerified
                            x-readme-ref-name: BankAccountResponse
                    required:
                      - id
                      - userId
                      - status
                      - cryptoAmount
                      - fiatAmount
                      - exchangeRate
                      - tokenSymbol
                      - blockchainSymbol
                      - fiatCurrency
                      - createdAt
                      - completedAt
                      - destinationWalletAddress
                      - bankAccount
                    x-readme-ref-name: OnRampPartnerV2Response
              example:
                success: true
                data:
                  id: 63f51f11-6869-47b0-a109-ddb50ef20efb
                  userId: 8374f327-38bd-4b0b-b8a7-2524599eb903
                  status: PENDING_PAYMENT
                  cryptoAmount: 2500
                  fiatAmount: 50000
                  crossFiatAmount: 0
                  exchangeRate: 19.53964594161554
                  tokenSymbol: USDC
                  blockchainSymbol: POL
                  fiatCurrency: MXN
                  premiumSpread: 0.01
                  forwardingDays: 2
                  effectiveForwardingDays: 4
                  forwardingSettlementDate: '2026-03-14T03:25:27.495Z'
                  createdAt: '2025-05-14T10:00:00Z'
                  completedAt: null
                  destinationWalletAddress: '0x7796d4f304bd84171ee6730ad0f69c07a47e786d'
                  bankAccount:
                    country: MX
                    accountIdentifier: '014680260346007120'
                    bankName: Santander
                    isVerified: true
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                REQUIRED_USER_ID_ERROR:
                  value:
                    success: false
                    code: REQUIRED_USER_ID_ERROR
                    message: This endpoint requires a user id to be provided
                INVALID_USER_INPUT_ERROR:
                  value:
                    success: false
                    code: INVALID_USER_INPUT_ERROR
                    message: Invalid User Input
                BAD_REQUEST:
                  value:
                    success: false
                    code: BAD_REQUEST
                    message: Idempotency-Key must be 16-128 printable ASCII characters
                BAD_REQUEST_2:
                  value:
                    success: false
                    code: BAD_REQUEST
                    message: >-
                      Either quoteId or fiatCurrency, blockchainSymbol,
                      tokenSymbol, and at least one of fiatAmount or
                      cryptoAmount must be provided
                BAD_REQUEST_3:
                  value:
                    success: false
                    code: BAD_REQUEST
                    message: Fiat currency is disabled or does not exist
                BAD_REQUEST_4:
                  value:
                    success: false
                    code: BAD_REQUEST
                    message: >-
                      This blockchain and token combination is disabled or does
                      not exist
                BAD_REQUEST_5:
                  value:
                    success: false
                    code: BAD_REQUEST
                    message: Quote is not valid for ON_RAMP
                QUOTE_EXPIRED:
                  value:
                    success: false
                    code: QUOTE_EXPIRED
                    message: Quote has expired
                INVALID_FIAT_AMOUNT_ERROR:
                  value:
                    success: false
                    code: INVALID_FIAT_AMOUNT_ERROR
                    message: >-
                      Fiat amount {amount} is outside of the allowed range for
                      ON_RAMP. Should be between {min} and {max}
                INVALID_TOKEN_AMOUNT_ERROR:
                  value:
                    success: false
                    code: INVALID_TOKEN_AMOUNT_ERROR
                    message: >-
                      Token amount {amount} is outside of the allowed range for
                      ON_RAMP. Should be between {min} and {max}
                INVALID_TOKEN_OPERATION_ERROR:
                  value:
                    success: false
                    code: INVALID_TOKEN_OPERATION_ERROR
                    message: >-
                      Token {symbol} cannot be operated as OTC, only stable
                      coins are allowed
                BAD_REQUEST_6:
                  value:
                    success: false
                    code: BAD_REQUEST
                    message: >-
                      Cannot create transaction: No supported banks configured
                      for user with id: {userId}
                BAD_REQUEST_7:
                  value:
                    success: false
                    code: BAD_REQUEST
                    message: >-
                      Either walletAddressId or destinationWalletAddress must be
                      provided
        '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
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                USER_NOT_VERIFIED_ERROR:
                  value:
                    success: false
                    code: USER_NOT_VERIFIED_ERROR
                    message: >-
                      User is not allowed to perform the operations because has
                      not completed the KYC verification.
                RECEIVER_CANNOT_INITIATE_TRANSACTION:
                  value:
                    success: false
                    code: RECEIVER_CANNOT_INITIATE_TRANSACTION
                    message: Receiver accounts cannot initiate transactions directly.
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                code: NOT_FOUND_ERROR
                message: Requested resource was not found
        '409':
          description: Conflict
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                code: CONFLICT
                message: >-
                  A request with this idempotency key is currently being
                  processed
        '422':
          description: Unprocessable Entity
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                code: INVALID_USER_INPUT_ERROR
                message: Idempotency-Key was already used with a different request body
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                code: INTERNAL_SERVER_ERROR
                message: Internal server error
      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.

````