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

# Create a payment

> Opens a payment collected on behalf of the API key’s business and returns the funding instructions. method defaults to TOKEN, which requires chain and mint and returns the deposit address under token. For method=FIAT a currency must be supplied and the response carries the virtual account details under fiat. The payment stays AWAITING until the funds land, and a platform fee is charged on top of amount — the payer funds totalAmount and your balance is credited the amount share. Once it settles the payment is posted to the paymentWebhookURL configured on your API keys.

Collects money into your own business balance. Where an onramp or offramp order
moves value on behalf of one of your end users, a payment is you getting paid —
a checkout, a subscription charge, a top-up. Paj hands you somewhere to be paid
into, watches it, and credits your balance once the money lands.

Nothing in the request names your business: the `x-api-key` header already does,
and the payment is opened for whichever business the key belongs to.

## Being paid on-chain

`method` defaults to `TOKEN`, so the common case is a short request:

```json theme={null}
{
  "amount": 25,
  "chain": "SOLANA",
  "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
}
```

`amount` is in whole units of the token — `25` means 25 USDC, not 25 base
units. The response comes back with a `token` object holding the `address` to
pay, which is reserved for this payment and no other.

Token payments open on `SOLANA` and the five EVM chains — `ETHEREUM`, `BASE`,
`BSC`, `MONAD` and `ARC`. TON is not supported for payments yet, even though it
appears in the `chain` enum — a `TOKEN` payment on `TON` is a `400`. Use TON for
[onramp](/api-reference/create-onramp-order) and
[offramp](/api-reference/create-offramp-order) orders only. [Supported
chains](/concepts/chains) lists the USDC contract on each.

Your balance is held in USDC. A payment in USDC is credited as it lands; a
payment in any other token is swapped to USDC first, and the swap's output is
what is credited.

<Warning>
  Send the token named in `mint`, on the chain named in `chain`, to that address
  and nothing else. A different token arriving at the address is not recognised
  as paying the payment, and recovering it is a manual process.
</Warning>

## Being paid in fiat

Set `method` to `FIAT` and supply a `currency`, and the response carries a
`fiat` object instead: a virtual account number, the account name, and the bank
it sits with. Your payer transfers into it exactly as they would for an onramp
order.

<Note>
  Fiat payments are collected but are not yet added to your business balance,
  which is denominated in USDC. Until the conversion is settled, use `TOKEN` for
  anything that needs to reach your balance automatically.
</Note>

## The platform fee

Paj charges a fee on each payment, currently 1% of `amount`, and adds it **on
top** rather than taking it out. The response shows the split:

* **`amount`** — what you asked for, and the share that reaches your balance.
* **`fee`** — Paj's share, in the same units. Absent when no fee applies.
* **`totalAmount`** — `amount` plus `fee`, and what the payer must actually
  send.

Show your payer `totalAmount`, not `amount`. A payer who sends only `amount`
has underpaid, and the payment settles for less than you asked — the fee is
taken proportionally from whatever arrives, so a 25 USDC payment funded with
exactly 25 credits you about 24.75.

## The payment window

Every payment carries an `expiresAt`, 30 minutes out. Money that arrives inside
that window settles normally; a payment that reaches its expiry unpaid moves to
`EXPIRED`, and for on-chain payments the deposit address is released.

That release is the reason the deadline matters. An address belonging to an
expired payment is no longer being watched on that payment's behalf, so tokens
sent late are not credited automatically. Show the countdown to whoever is
paying, and open a fresh payment rather than reusing an address once the first
one lapses.

## Following the payment

`status` starts at `AWAITING`. When a deposit is seen it becomes `PROCESSING`
while the funds are swept into Paj's pool, then `SUCCESSFUL` once that
completes and your balance has been credited. `EXPIRED` and `ERROR` are
terminal.

You do not have to poll for that. Set a `paymentWebhookURL` on your API key and
Paj `POST`s the settled payment to it — the same body this endpoint returned,
with `status` now `SUCCESSFUL`, so you can match it to the payment you opened by
`id`. It is separate from the `rampWebhookURL` that carries onramp and offramp
order updates, because the two payloads differ; a key can have one, both, or
neither.
If several of your keys name a payment webhook, each distinct URL is called.

Any `2xx` from your endpoint counts as delivered. Anything else — a `4xx`, a
`5xx`, or a connection that never opens — is retried every 30 seconds, up to
five attempts in total, after which the payment is left settled and the delivery
is abandoned. Return a `2xx` as soon as you have durably recorded the payment
and do the rest of your work afterwards; a slow handler that eventually answers
`500` costs you the next two minutes of retries.

Retries live in the process that saw the settlement, so a deploy mid-window ends
them. Treat the webhook as a prompt rather than a ledger, and let your own
records be the authority.

The credited amount follows what actually arrived, not what you asked for. If a
payer sends 24.5 USDC against a payment whose `totalAmount` is 25.25, the
payment settles for 24.5 and your balance is credited that less the fee —
reconcile against the settled amount rather than assuming the requested one.

Your balance accumulates across payments and is withdrawn from the Paj
dashboard, not through this API.


## OpenAPI

````yaml POST /pub/v2/payment
openapi: 3.0.0
info:
  title: Paj Public API
  description: >-
    Programmatic access to Paj's on/off ramp. Register a Nigerian bank account,
    get

    the on-chain address that pays it, create offramp orders for a specific
    amount,

    and read the live conversion rates.


    Every request must carry an `x-api-key` header. Keys are scoped to a
    business,

    and the rates you receive already have that business's fee applied.
  version: 2.0.0
  contact: {}
servers:
  - url: https://api.paj.cash
    description: Production
security: []
tags: []
paths:
  /pub/v2/payment:
    post:
      tags:
        - Pub V2
      summary: Create a payment
      description: >-
        Opens a payment collected on behalf of the API key’s business and
        returns the funding instructions. method defaults to TOKEN, which
        requires chain and mint and returns the deposit address under token. For
        method=FIAT a currency must be supplied and the response carries the
        virtual account details under fiat. The payment stays AWAITING until the
        funds land, and a platform fee is charged on top of amount — the payer
        funds totalAmount and your balance is credited the amount share. Once it
        settles the payment is posted to the paymentWebhookURL configured on
        your API keys.
      operationId: PubV2Controller_createPayment
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreatePaymentV2Dto'
      responses:
        '201':
          description: The pending payment with funding instructions (fiat or token).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentResponseDto'
        '400':
          description: >-
            The amount was not positive, or the method was missing its currency
            (FIAT) or chain and mint (TOKEN)
        '401':
          description: Missing or invalid API key (x-api-key header)
      security:
        - x-api-key: []
components:
  schemas:
    CreatePaymentV2Dto:
      type: object
      properties:
        amount:
          type: number
          description: Amount to collect, in whole units. Must be positive.
          example: 100
        currency:
          type: string
          enum:
            - NGN
            - GHS
            - TZS
            - KES
            - ZAR
            - USD
          description: >-
            Fiat currency to charge. Required when `method=FIAT`; ignored for
            `TOKEN`.
        chain:
          type: string
          enum:
            - SOLANA
            - MONAD
            - ETHEREUM
            - BSC
            - BASE
            - ARC
            - ZCASH
            - TON
          description: >-
            Chain to receive the token on. Required when `method=TOKEN`; ignored
            for `FIAT`.
        mint:
          type: string
          description: >-
            Mint/contract address of the token on the selected `chain`. Required
            when `method=TOKEN`.
          example: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
        method:
          type: string
          enum:
            - FIAT
            - TOKEN
          default: TOKEN
          description: >-
            How the payment is funded. Defaults to `TOKEN`, which issues a
            deposit address and requires `chain` and `mint`. `FIAT` issues a
            virtual account and requires `currency`.
      required:
        - amount
    PaymentResponseDto:
      type: object
      properties:
        id:
          type: string
          description: Payment id. Subscribe to live updates with it.
          example: 507f1f77bcf86cd799439011
        method:
          type: string
          enum:
            - FIAT
            - TOKEN
        status:
          type: string
          enum:
            - INIT
            - AWAITING
            - PROCESSING
            - SUCCESSFUL
            - EXPIRED
            - ERROR
        amount:
          type: string
          description: >-
            Requested amount, in whole units of the currency or token (the
            stored base units scaled back down by `details.decimals`).
          example: 100
        fee:
          type: number
          description: >-
            Platform fee charged on top of `amount`, in the same units. Absent
            when the payment carries no fee.
          example: 1
        totalAmount:
          type: string
          description: >-
            What the payer must fund: `amount` plus any `fee`. Equal to `amount`
            when no fee was charged.
          example: 101
        expiresAt:
          format: date-time
          type: string
          description: When the payment window closes.
        fiat:
          description: Fiat funding details. Present when method=FIAT.
          allOf:
            - $ref: '#/components/schemas/PaymentFiatDto'
        token:
          description: On-chain funding details. Present when method=TOKEN.
          allOf:
            - $ref: '#/components/schemas/PaymentTokenDto'
      required:
        - id
        - method
        - status
        - amount
        - totalAmount
    PaymentFiatDto:
      type: object
      properties:
        currency:
          type: string
          enum:
            - NGN
            - GHS
            - TZS
            - KES
            - ZAR
            - USD
        accountNumber:
          type: string
          description: Virtual account number to fund the payment.
        accountName:
          type: string
          description: Name on the virtual account.
        bank:
          description: The bank the virtual account belongs to.
          allOf:
            - $ref: '#/components/schemas/BankResDto'
      required:
        - currency
        - accountNumber
    PaymentTokenDto:
      type: object
      properties:
        chain:
          type: string
          enum:
            - SOLANA
            - MONAD
            - ETHEREUM
            - BSC
            - BASE
            - ARC
            - ZCASH
            - TON
        mint:
          type: string
          description: USDC mint/contract address on the chain.
        address:
          type: string
          description: Deposit address to send USDC to.
      required:
        - chain
        - mint
        - address
    BankResDto:
      type: object
      properties:
        id:
          type: string
          description: Bank id
          example: Bank of America
        name:
          type: string
          description: Bank name
          example: Bank of America
        country:
          type: string
          description: Country of the bank
          example: NG
        code:
          type: string
          description: Bank code
          example: '001'
        logo:
          type: string
          description: Bank logo URL
          example: https://example.com/logo.png
          nullable: true
      required:
        - id
        - name
        - country
        - code
  securitySchemes:
    x-api-key:
      type: apiKey
      in: header
      name: x-api-key

````

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