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

# API Flows at a Glance

> Numbered sequence diagrams for every Kotani Pay API product — auth, customers, onramp, offramp, deposits, withdrawals, payment links, settlements, and bulk payments

One sequence diagram per flow. Use these for a quick visual of who calls what, and in what order. Each product also has a detailed guide in the **Products** section.

> [!NOTE]
>
> Rate is a single call with no branching, so it isn't diagrammed on its own — it appears as a step inside the flows that need it.

***

## 1. Auth — Get an API Key

Server-to-server auth: get an API key once via the magic-link flow, then use that key in every other call. A key can also be generated directly from the dashboard's **API Keys** page — choose **Integrator Level** (not User Bound) for full access to every endpoint.

`/api/v3/auth`

**Magic link → JWT → API key.** `/auth/api-key` returns the key alone; `/auth/api-key/secure` also returns a secret for request signing. The JWT expires after 1 hour — use the refresh endpoint rather than repeating the magic-link flow.

```mermaid theme={null}
sequenceDiagram
    participant Integrator
    participant Kotani Pay

    Integrator->>Kotani Pay: 1. POST /auth/login (email)
    Kotani Pay-->>Integrator: magic link sent to email

    Integrator->>Kotani Pay: 2. Click magic link → GET /auth/verify?hash=...

    opt Link flagged as suspicious
        Kotani Pay-->>Integrator: human verification required
        Integrator->>Kotani Pay: POST /auth/human-verify
    end

    Kotani Pay-->>Integrator: token (JWT) + refresh_token

    alt Key only
        Integrator->>Kotani Pay: 3. GET /auth/api-key (Bearer JWT)
        Kotani Pay-->>Integrator: API key
    else Key + secret, for request signing
        Integrator->>Kotani Pay: 3. GET /auth/api-key/secure (Bearer JWT)
        Kotani Pay-->>Integrator: API key + secret
    end

    Note over Integrator,Kotani Pay: 4. Use API key in the Authorization header<br/>on every request below

    opt JWT expires after 1 hour
        Integrator->>Kotani Pay: GET /auth/refresh-token
        Kotani Pay-->>Integrator: new token
    end
```

***

## 2. Customer — Create Once, Reuse Everywhere

Almost every product below needs a `customer_key`. Create the record once per person, then pass that key into deposits, withdrawals, and settlement requests.

`/api/v3/customer`

**Create → reuse the key.** Mobile money and bank customers follow the same shape, on `/customer/mobile-money` and `/customer/bank`.

```mermaid theme={null}
sequenceDiagram
    participant Integrator
    participant Kotani Pay

    Integrator->>Kotani Pay: 1. POST /customer/mobile-money (name, phone, network, country)
    Kotani Pay-->>Integrator: customer_key

    Note over Integrator,Kotani Pay: reuse customer_key on deposit, withdraw<br/>and settlement requests

    opt Details change later
        Integrator->>Kotani Pay: 2. PATCH /customer/mobile-money/:customer_key
    end
```

***

## 3. Onramp — Fiat → Crypto

Customer pays in local currency; Kotani Pay converts at a locked rate and sends crypto to the wallet address you provided.

`/api/v3/onramp`

**Rate quote → payment → crypto delivery.** Mobile money and bank checkout both converge on the same delivery step.

```mermaid theme={null}
sequenceDiagram
    participant Integrator
    participant Kotani Pay
    participant Customer

    Integrator->>Kotani Pay: 1. GET /rates/onramp-rate
    Kotani Pay-->>Integrator: exchange rate

    Integrator->>Kotani Pay: 2. POST /onramp (wallet address, callbackUrl)
    Kotani Pay-->>Integrator: PENDING + payment instructions

    Kotani Pay->>Customer: 3. STK push / USSD / bank checkout link
    Customer->>Kotani Pay: confirms payment (PIN / bank auth)

    Kotani Pay->>Kotani Pay: 4. Convert fiat to crypto at locked rate
    Kotani Pay->>Customer: 5. Send crypto to wallet

    Kotani Pay-->>Integrator: 6. Webhook: SUCCESS / FAILED
```

***

## 4. Offramp — Crypto → Fiat

Customer sends crypto to an escrow address; once confirmed on-chain, Kotani Pay disburses fiat via mobile money or bank.

`/api/v3/offramp`

**Deposit address → on-chain confirm → fiat disbursed.** A failed disbursement triggers an automatic crypto refund.

```mermaid theme={null}
sequenceDiagram
    participant Integrator
    participant Kotani Pay
    participant Customer

    Integrator->>Kotani Pay: 1. GET /rates/offramp-rate
    Kotani Pay-->>Integrator: exchange rate

    Integrator->>Kotani Pay: 2. POST /offramp (callbackUrl)
    Kotani Pay-->>Integrator: PENDING + depositAddress

    Integrator->>Customer: 3. Show deposit address / QR
    Customer->>Kotani Pay: 4. Sends crypto to depositAddress

    Kotani Pay->>Kotani Pay: 5. Confirm on-chain, disburse fiat
    Kotani Pay->>Customer: fiat delivered (mobile money / bank)

    alt Disbursement fails
        Kotani Pay->>Kotani Pay: auto-refund crypto after 5 min
        Kotani Pay-->>Integrator: Webhook: REFUNDED
    else Disbursement succeeds
        Kotani Pay-->>Integrator: 6. Webhook: SUCCESS
    end
```

***

## 5. Deposit — Collect Payment

Four collection methods. All four credit the same deposit balance and notify the same way — only the customer-facing step differs.

`/api/v3/deposit`

### 5a. Mobile Money

STK push (M-PESA / Airtel) or USSD prompt (MTN and others).

```mermaid theme={null}
sequenceDiagram
    participant Integrator
    participant Kotani Pay
    participant Customer

    Integrator->>Kotani Pay: 1. POST /deposit/mobile-money (callbackUrl)
    Kotani Pay-->>Integrator: PENDING

    Kotani Pay->>Customer: 2. STK push / USSD prompt
    Customer->>Kotani Pay: 3. Enters PIN to confirm

    Kotani Pay-->>Integrator: 4. Webhook: SUCCESSFUL / FAILED
    Integrator->>Kotani Pay: 5. GET /deposit/mobile-money/status (optional poll)
```

### 5b. Bank Checkout

One endpoint, three response shapes — what the customer sees depends on the currency.

```mermaid theme={null}
sequenceDiagram
    participant Integrator
    participant Kotani Pay
    participant Customer

    Integrator->>Kotani Pay: 1. POST /deposit/bank-checkout (callbackUrl)

    alt Currency: ZAR
        Kotani Pay-->>Integrator: checkoutUrl
        Integrator->>Customer: 2. Redirect to checkoutUrl
        Customer->>Kotani Pay: 3. Completes payment on bank's hosted page
    else Currency: KES
        Kotani Pay-->>Integrator: PesaLink account + reference
        Integrator->>Customer: 2. Show account details + reference
        Customer->>Kotani Pay: 3. Sends transfer from own banking app
    else Currency: NGN
        Kotani Pay-->>Integrator: dedicated virtual account (expires)
        Integrator->>Customer: 2. Show virtual account details
        Customer->>Kotani Pay: 3. Transfers to virtual account before expiry
    end

    Kotani Pay-->>Integrator: 4. Webhook: SUCCESSFUL / FAILED
```

### 5c. Card

3D Secure runs inline only when the issuer requires it.

```mermaid theme={null}
sequenceDiagram
    participant Integrator
    participant Kotani Pay
    participant Customer

    Integrator->>Kotani Pay: 1. POST /deposit/card
    Kotani Pay-->>Integrator: PENDING (+ 3DS redirect if required)

    opt 3DS required
        Integrator->>Customer: 2. Redirect for 3D Secure
        Customer->>Kotani Pay: authenticates
    end

    Kotani Pay-->>Integrator: 3. Webhook: charge settled
```

### 5d. On-Chain (Receive Crypto)

For merchants who want to receive crypto themselves, not sell it to customers — the reverse of Onramp.

```mermaid theme={null}
sequenceDiagram
    participant Integrator
    participant Kotani Pay
    participant Customer

    Integrator->>Kotani Pay: 1. POST /deposit/on-chain (wallet_id, chain, token, callbackUrl)
    Kotani Pay->>Customer: 2. STK push
    Customer->>Kotani Pay: 3. Enters PIN to confirm

    Kotani Pay->>Kotani Pay: 4. Convert fiat to crypto at current rate
    Kotani Pay->>Integrator: 5. Send crypto to your wallet (or public_address if provided)

    Kotani Pay-->>Integrator: 6. Webhook: SUCCESSFUL / FAILED
```

***

## 6. Withdraw — Disburse to a Customer

Money moves out of your payout balance. A failed disbursement automatically reverses the debit.

`/api/v3/withdraw`

### 6a. Mobile Money

Same flow for `/lipa-na-mpesa` and `/paybill` — Kenya-only variants of this endpoint.

```mermaid theme={null}
sequenceDiagram
    participant Integrator
    participant Kotani Pay
    participant Recipient

    Integrator->>Kotani Pay: 1. POST /withdraw/mobile-money (callbackUrl)
    Kotani Pay->>Kotani Pay: 2. Debit payout balance
    Kotani Pay-->>Integrator: PENDING

    Kotani Pay->>Recipient: 3. Disburse funds
    Recipient-->>Kotani Pay: SMS confirmation

    alt Disbursement succeeds
        Kotani Pay-->>Integrator: 4. Webhook: SUCCESSFUL
    else Disbursement fails
        Kotani Pay->>Kotani Pay: auto-reverse payout balance
        Kotani Pay-->>Integrator: 4. Webhook: FAILED
    end
```

### 6b. Bank

Kenya and South Africa only. Look up bank codes for your currency before initiating.

```mermaid theme={null}
sequenceDiagram
    participant Integrator
    participant Kotani Pay
    participant Recipient

    Integrator->>Kotani Pay: 1. GET /withdraw/v2/bank/supporting-banks/:currency
    Kotani Pay-->>Integrator: bank codes for that currency

    Integrator->>Kotani Pay: 2. POST /withdraw/v2/bank
    Kotani Pay-->>Integrator: PENDING

    Kotani Pay->>Recipient: 3. Transfer to bank account
    Kotani Pay-->>Integrator: 4. Webhook: settled / failed
```

***

## 7. Payment Links — Hosted Checkout

A no-code checkout page. One create call, then Kotani Pay handles everything the customer sees.

`/api/v3/payment-links`

**Create link → customer pays → webhook.** Backed by the same deposit transactions as section 5.

```mermaid theme={null}
sequenceDiagram
    participant Integrator
    participant Kotani Pay
    participant Customer

    Integrator->>Kotani Pay: 1. POST /payment-links (pricing, methods, limit)
    Kotani Pay-->>Integrator: link URL

    Integrator->>Customer: 2. Share link (SMS / email / social)
    Customer->>Kotani Pay: 3. Opens link, picks a payment method
    Customer->>Kotani Pay: 4. Pays (mobile money / bank / card / crypto)

    Kotani Pay-->>Integrator: 5. Webhook: transaction.deposit.status.updated
```

***

## 8. Settlements — Move Balance Out

Every settlement goes through manual review before funds move. Batch and merge exist to handle many at once.

`/api/v3/integrator/settlements`

### 8a. Single Settlement

Check the schedule and fee before you submit — both are read endpoints.

```mermaid theme={null}
sequenceDiagram
    participant Integrator
    participant Kotani Pay
    participant Reviewer as Kotani Pay Agent

    Integrator->>Kotani Pay: 1. GET /settlements/schedule
    Kotani Pay-->>Integrator: enabled, min/max limits

    Integrator->>Kotani Pay: 2. GET /settlements/fee-preview
    Kotani Pay-->>Integrator: fee, net amount

    Integrator->>Kotani Pay: 3. POST /settlements
    Kotani Pay-->>Integrator: PENDING

    Kotani Pay->>Reviewer: 4. Manual review
    Reviewer-->>Kotani Pay: APPROVED / REJECTED

    alt Approved
        Kotani Pay->>Kotani Pay: 5. Disburse to destination
        Kotani Pay-->>Integrator: PROCESSED
    else Rejected
        Kotani Pay-->>Integrator: REJECTED (reason)
    end
```

### 8b. Batch Settlement

Each child settlement is reviewed independently; the batch status reflects the mix.

```mermaid theme={null}
sequenceDiagram
    participant Integrator
    participant Kotani Pay

    Integrator->>Kotani Pay: 1. POST /settlements/batch (requests[])
    Kotani Pay-->>Integrator: batchId, PENDING children

    Kotani Pay->>Kotani Pay: 2. Review and process each child

    alt All children processed
        Kotani Pay-->>Integrator: Webhook: settlement.batch.processed
    else Mixed outcome
        Kotani Pay-->>Integrator: Webhook: settlement.batch.partial
    else All rejected
        Kotani Pay-->>Integrator: Webhook: settlement.batch.rejected
    end

    Integrator->>Kotani Pay: 3. GET /settlements/batch/:batchId (track)
```

### 8c. Merge

Groups existing settlements into a batch after the fact — this cannot be undone.

```mermaid theme={null}
sequenceDiagram
    participant Integrator
    participant Kotani Pay

    Integrator->>Kotani Pay: 1. POST /settlements/merge (settlementIds[])
    Note right of Integrator: all must be PENDING or UNDER_REVIEW
    Kotani Pay->>Kotani Pay: 2. Group into a new batch
    Kotani Pay-->>Integrator: new batchId
```

***

## 9. Bulk Payments — Many Recipients at Once

Upload a CSV, get it validated and batched, then Kotani Pay disburses asynchronously — one batch per currency.

`/api/v3/bulk-payments`

**Validate → preview → create → disburse.** Each individual payment still fires its own withdrawal webhook.

```mermaid theme={null}
sequenceDiagram
    participant Integrator
    participant Kotani Pay
    participant Recipients

    Integrator->>Kotani Pay: 1. POST /bulk-payments/validate-csv
    Kotani Pay-->>Integrator: row errors + currency totals

    Integrator->>Kotani Pay: 2. POST /bulk-payments/preview-batches
    Kotani Pay-->>Integrator: batch breakdown per currency

    Integrator->>Kotani Pay: 3. POST /bulk-payments/create-batches (assign wallets)
    Kotani Pay-->>Integrator: transactionId, batchIds

    Kotani Pay->>Recipients: 4. Disburse each payment (async)
    Kotani Pay-->>Integrator: 5. Webhook per payment (withdrawal.status.updated)

    Integrator->>Kotani Pay: 6. GET /bulk-payments/batches/:batchId (track)
```


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