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

# INR Offramp

> Sell stablecoin for Indian Rupees, paid out directly to an Indian bank account via IMPS, NEFT, or RTGS.

INR offramp lets your users convert their stablecoin balance into Indian Rupees, settled to a bank account in India. Every offramp flow follows the same four steps: **Create User → KYC → Bank Account Linkage → Transaction.**

<Info>
  Both USDT and USDC are supported for INR offramp.
</Info>

<Steps>
  <Step title="Create User">
    ```http theme={null}
    POST /api/v2/user
    ```

    ```json theme={null}
    {
      "email": "user@example.com",
      "phone": "+919876543210"
    }
    ```

    Response:

    ```json theme={null}
    {
      "success": true,
      "data": {
        "user_id": "550e8400-e29b-41d4-a716-446655440000"
      }
    }
    ```

    Save `user_id` — every subsequent call needs it as the `X-User-Id` header.
  </Step>

  <Step title="KYC">
    INR supports two KYC methods:

    <Tabs>
      <Tab title="KYC Sharing">
        ```http theme={null}
        POST /api/v2/user/kyc
        ```

        Headers: `X-User-Id: <user_id>`

        ```json theme={null}
        {
          "legal_name": "John Doe",
          "poi": "DWSPP6492L",
          "poa": "500100121232",
          "dob": "31-01-2000",
          "email": "user@example.com",
          "phone": "+919876543210",
          "country_iso3": "IND",
          "is_nri": false
        }
        ```

        Response:

        ```json theme={null}
        { "success": true, "data": {} }
        ```

        `poi` = PAN, `poa` = Aadhaar.

        <Note>
          Set `is_nri: true` if the user is a Non-Resident Indian. TDS is not deducted from INR sell payouts for NRI users; it is deducted for third-party payouts to Indian residents. A user whose `country` is India cannot be marked `is_nri: true`.
        </Note>

        Saber may request supporting KYC documents for a KYC-Sharing user at any time — these must be shared within 72 hours of the request.
      </Tab>

      <Tab title="KYC Widget">
        Redirect the user to a signed URL:

        ```javascript theme={null}
        const sigString = clientId + timestamp + "sdk" + userId
        const secret = HmacSHA256(sigString, clientSecret).toString().toUpperCase()
        // redirect to: https://app.saber.money/kyc?client_id=...&user_id=...&timestamp=...&secret=...&redirect_url=<url-encoded-url>
        ```

        The URL is valid for **10 minutes** from generation. Append the optional `redirect_url` as the last query parameter (URL-encoded) to send the user back to your app when they exit the flow. See [KYC Hosted Widget](/user/kyc/widget) for the full parameter reference.
      </Tab>
    </Tabs>
  </Step>

  <Step title="Bank Account Linkage">
    ```http theme={null}
    POST /api/v2/user/bank_account
    ```

    Headers: `X-User-Id: <user_id>`

    ```json theme={null}
    {
      "account_number": "12345678901234",
      "bank_code": "HDFC0001234",
      "country": "IND"
    }
    ```

    For India, only `account_number` and `bank_code` (IFSC) are required — `account_holder_name` is not required at this step; the account holder name is fetched from the bank during penny-drop and matched against the user's KYC `legal_name` instead.

    Response:

    ```json theme={null}
    {
      "success": true,
      "data": {
        "bank_id": "550e8400-e29b-41d4-a716-446655440000",
        "account_number": "12XXXXX1234",
        "ifsc_code": "HDFC0001234",
        "account_holder_name": "John Doe",
        "account_type": "SAVINGS",
        "name": "HDFC Bank",
        "iban": null,
        "bic": null,
        "validation_status": "PENDING",
        "routing_type": "IFSC",
        "created_at": "2024-01-01T00:00:00Z",
        "updated_at": "2024-01-01T00:00:00Z",
        "message": ""
      }
    }
    ```

    `created_at`/`updated_at` here are ISO 8601 date strings — unlike wallet-transaction endpoints, which use epoch milliseconds. Save `bank_id` for the sell step.

    <Warning>
      Indian bank accounts go to `validation_status: PENDING` and are validated asynchronously via **penny-drop**: Saber sends ₹1 to the account to confirm it exists, then fuzzy-matches the fetched account holder name against the user's KYC `legal_name`. The account is only marked `APPROVED` if the names match; otherwise it's `NAME_REJECTED`.
    </Warning>

    <Note>
      A user can have up to **4 `APPROVED` bank accounts** at any point in time (error `304012` when exceeded).
    </Note>
  </Step>

  <Step title="Transaction">
    Min ₹100 per transaction; max depends on the user's assigned limits (see [User Limits & EDD](#user-limits-and-edd) below). `payment_method: bank_transfer` resolves internally to one of:

    * **IMPS** — for amounts from ₹100 up to ₹5,00,000. Instant, no cut-off times.
    * **NEFT / RTGS** — for amounts above ₹5,00,000. Manual processing, \~12 hour SLA, operates 10 AM–6 PM IST. Support over weekends and public holidays may be limited.

    Two variants, both requiring a quote first — a **Live Quote** (informational, executes at market rate regardless) or a **Locked Quote** (rate held \~30-60s, supplied as `quote_id` in the sell request):

    <Tabs>
      <Tab title="Pool Sell (recommended)">
        Get an informational quote:

        ```http theme={null}
        GET /api/v2/wallet/s/quote?from_currency=USDT&to_currency=INR&from_amount=100
        ```

        ```json theme={null}
        {
          "success": true,
          "data": {
            "from_currency": "USDT",
            "to_currency": "INR",
            "from_amount": 100,
            "pre_fee_to_amount": 8650,
            "to_amount": 8600,
            "base_price": 86.5,
            "final_price": 86,
            "total_fee": 50,
            "fee_currency": "INR",
            "fee_breakup": {
              "platform_fee": 20,
              "network_fee": 0,
              "client_fee": 10,
              "discount": 0,
              "tax_on_fee": 20,
              "tds": 0
            }
          }
        }
        ```

        Then create the sell:

        ```http theme={null}
        POST /api/v2/wallet/transaction/pool/sell
        ```

        ```json theme={null}
        {
          "source_id": "<bank_id>",
          "fiat_symbol": "INR",
          "crypto_symbol": "USDT",
          "crypto_amount": 25,
          "payment_method": "bank_transfer"
        }
        ```

        Response:

        ```json theme={null}
        {
          "success": true,
          "data": {
            "id": "07825d5d-1879-4cc7-a87f-f5ed45ee391b",
            "transaction_type": "POOL_SELL",
            "status": "PROCESSING",
            "fiat_amount": 2160.5,
            "crypto_amount": 25,
            "fiat_symbol": "INR",
            "crypto_symbol": "USDT",
            "exchange_rate": 86.42,
            "failure_code": "",
            "failure_desc": "",
            "created_at": 1774343695000,
            "user_id": "65d246fc-6a5b-43d7-89bf-944e95ff2279"
          }
        }
        ```
      </Tab>

      <Tab title="External Sell">
        Generate a locked quote (expires in \~30-60s):

        ```http theme={null}
        GET /api/v2/wallet/w/quote?from_currency=USDT&to_currency=INR&network=BSC&from_amount=10
        ```

        ```json theme={null}
        {
          "success": true,
          "data": {
            "from_currency": "USDT",
            "to_currency": "INR",
            "network": "BSC",
            "from_amount": 10,
            "pre_fee_to_amount": 863.2,
            "to_amount": 863.2,
            "base_price": 86.32,
            "final_price": 86.32,
            "total_fee": 0,
            "fee_currency": "INR",
            "fee_breakup": {
              "platform_fee": 0,
              "network_fee": 0,
              "client_fee": 0,
              "discount": 0,
              "tax_on_fee": 0,
              "tds": 0
            },
            "other_details": {
              "fiat_settlement_time": { "min": 0, "max": 1, "unit": "HOURS" }
            },
            "transaction_type": "EXTERNAL_SELL",
            "id": "0c6ad6d3-6902-4a27-a30f-c176456a0835",
            "expiry": "2026-03-25T09:42:14.321113044Z",
            "settlement_expiry": "2026-03-25T10:41:44.321113044Z",
            "created_at": "2026-03-25T09:41:44.318189513Z",
            "updated_at": "2026-03-25T09:41:44.318189595Z"
          }
        }
        ```

        Save `id` from the response as `quote_id`, then create the sell:

        ```http theme={null}
        POST /api/v2/wallet/transaction/crypto/sell
        ```

        ```json theme={null}
        {
          "payment_method": "bank_transfer",
          "network": "BSC",
          "destination_instrument_id": "<bank_id>",
          "quote_id": "<quote_id>",
          "sender_wallet_address": "0x318d2aae4c99c2e74f7b5949fa1c34df837789b8",
          "refund_wallet_address": "0x318d2aae4c99c2e74f7b5949fa1c34df837789b8"
        }
        ```

        Response:

        ```json theme={null}
        {
          "success": true,
          "data": {
            "id": "01992e48-db7d-7c55-bb87-6f4e1abf5fe3",
            "status": "CREATED",
            "fiat_symbol": "INR",
            "crypto_symbol": "USDT",
            "fiat_amount": 863.2,
            "crypto_amount": 10,
            "payment_method": "bank_transfer",
            "deposit_crypto_address": "0xabcdef1234567890abcdef1234567890abcdef12",
            "deposit_network": "BSC",
            "destination_instrument_id": "a4680ba9-5ac6-4629-9493-2a88b160cd33",
            "refund_wallet_address": "0x318d2aae4c99c2e74f7b5949fa1c34df837789b8",
            "refund_network": "",
            "refund_tag": "",
            "sender_wallet_address": "0x318d2aae4c99c2e74f7b5949fa1c34df837789b8",
            "created_at": 1757418150839,
            "updated_at": 1757418150841
          }
        }
        ```

        Then fund `deposit_crypto_address` on-chain within the settlement expiry, and confirm it:

        ```http theme={null}
        POST /api/v2/wallet/transaction/crypto/sell/{id}/confirm-onchain-funding
        ```

        ```json theme={null}
        { "transaction_hash": "0x1234567890abcdef" }
        ```

        <Warning>
          This returns **202 Accepted**, not 200 — Saber verifies the deposit asynchronously.
        </Warning>

        ```json theme={null}
        {
          "success": true,
          "data": {
            "id": "01992e48-db7d-7c55-bb87-6f4e1abf5fe3",
            "status": "CREATED",
            "transaction_hash": "0x1234567890abcdef",
            "fiat_symbol": "INR",
            "crypto_symbol": "USDT"
          }
        }
        ```
      </Tab>
    </Tabs>
  </Step>
</Steps>

## Payouts to NRE accounts

Paying out to an NRE (Non-Resident External) bank account uses the same transaction flow with a few additional conditions — see [Traditional Rails](/offramp/currencies/inr-traditional).

## Checking status

```http theme={null}
GET /api/v2/wallet/transaction?transaction_type={POOL_SELL|EXTERNAL_SELL}&transaction_id={id}
```

| Transaction Type | Possible `status` values                                                                                                                                           |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Pool Sell        | `CREATED`, `PROCESSING`, `COMPLETED`, `FAILED`, `CANCELLED`, `APPROVAL_REQUIRED`, `SOURCE_INVALID`, `VERIFICATION_PENDING`, `REFUND_INITIATED`, `REFUND_COMPLETED` |
| External Sell    | `CREATED`, `PAYMENT_INITIATED`, `FUNDS_RECEIVED`, `COMPLETED`, `FAILED`, `REFUND_INITIATED`, `REFUND_COMPLETED`, `REFUND_FAILED`                                   |

<Accordion title="Example status responses">
  Pool Sell:

  ```json theme={null}
  {
    "success": true,
    "data": {
      "transaction_type": "POOL_SELL",
      "status": "COMPLETED",
      "created_at": 1742207345000,
      "updated_at": 1742207346000,
      "id": "0195a3a6-62c2-766b-b984-7f9f1754b3f1",
      "crypto_symbol": "USDT",
      "fiat_symbol": "INR",
      "exchange_rate": 84.56973573047619,
      "crypto_amount": 21,
      "fiat_amount": 1775.96445034,
      "bank_transaction_id": "1234",
      "source_id": ""
    }
  }
  ```

  External Sell:

  ```json theme={null}
  {
    "success": true,
    "data": {
      "id": "01992e48-db7d-7c55-bb87-6f4e1abf5fe3",
      "transaction_type": "EXTERNAL_SELL",
      "status": "FUNDS_RECEIVED",
      "created_at": 1757418150839,
      "updated_at": 1757418150841,
      "crypto_symbol": "USDT",
      "fiat_symbol": "INR",
      "crypto_amount": 0.695712,
      "fiat_amount": 55.38,
      "deposit_crypto_address": "0xabcdef1234567890abcdef1234567890abcdef12",
      "deposit_network": "BSC",
      "destination_instrument_id": "a4680ba9-5ac6-4629-9493-2a88b160cd33",
      "bank_transaction_id": "",
      "source_id": ""
    }
  }
  ```
</Accordion>

Poll until the status reaches a terminal state, or configure a webhook URL to receive completion pushes instead — see [Order Lifecycle and Webhooks](/offramp/operations/lifecycle).

## User limits and EDD

Each user has a lifetime transaction limit (currently \$200,000 USD equivalent — this figure is suggestive and subject to change; confirm current limits with Saber). Once a user's limit is breached, no further transactions can be created until Enhanced Due Diligence (EDD) is completed to raise it.

EDD is completed via the [EDD Hosted Widget](/users/limits-edd/widget), with a turnaround time of 2-3 working days.

## Related pages

<CardGroup cols={2}>
  <Card title="Traditional Rails (NRE Payouts)" icon="building-columns" href="/offramp/currencies/inr-traditional" cta="View guide" arrow="true" />

  <Card title="Offramp Operations" icon="arrow-right-arrow-left" href="/offramp/available-flows" cta="View guide" arrow="true" />

  <Card title="User KYC" icon="id-card" href="/user/kyc/overview" cta="View guide" arrow="true" />

  <Card title="Bank Account" icon="building-columns" href="/user/bank-account/overview" cta="View guide" arrow="true" />
</CardGroup>


## Related topics

- [Traditional Rails](/offramp/currencies/inr-traditional.md)
- [Available Flows](/offramp/available-flows.md)
- [Overview](/offramp/overview.md)
- [Fetching Transaction Status](/offramp/operations/fetch-status.md)
