---
title: "UPI Cash Withdrawal — API Recipe"
description: "Generate a single-use UPI QR for the withdrawal amount, show it to the customer, then poll the status API on the returned schedule — hand over cash only when `tx_status` is \"0\"."
canonical: "https://eps.eko.in/recipe/upi-cash-withdrawal"
---


> **Canonical URL:** https://eps.eko.in/recipe/upi-cash-withdrawal
> This is a machine-readable Markdown version of the page for AI agents and LLMs. The primary (HTML) version lives at the canonical URL above.

# UPI Cash Withdrawal — API Recipe

Generate a single-use UPI QR for the withdrawal amount, show it to the customer, then poll the status API on the returned schedule — hand over cash only when `tx_status` is "0".

> Product & pricing details: [UPI Cash Withdrawal](https://eps.eko.in/products/upi-cash-withdrawal-api.md)

## Flow

```mermaid
flowchart TD
  s1["POST Generate UPI QR for Cash Withdrawal"]
  s2["POST UPI Cash Withdrawal Status"]
  done(["done"])
  s1 -->|"response_type_id 99012: QR issued — wait `status_check_start_in` seconds, then poll."| s2
  s1 -->|"response_type_id 99014: Initiation failed — stop, do not dispense. Log and show `data.description`."| done
  s1 -->|"response_type_id 99015: Invalid amount — stop, fix the amount; nothing to poll."| done
  s1 -->|"response_type_id 99016: Not enabled for this retailer — stop; a provisioning task, retrying won't help."| done
  s2 -->|"response_type_id 99013: Paid — dispense the cash and store `bank_ref_num`."| done
  s2 -->|"response_type_id 99018: Failed — nothing debited; do not dispense."| done
```

## Steps

1. `POST` **[Generate UPI QR for Cash Withdrawal](https://eps.eko.in/docs/upi-cash-withdrawal.md)** — Validate the amount first (₹100–₹5,000, multiples of ₹100, no paise), then send it with the retailer's live GPS fix. Render `qr_string` as `data:image/png;base64,…` for the customer to scan from a second device, and persist `tid`. A QR means no money has moved yet. Never show a QR twice or re-initiate against the same `tid`. On a timeout with no `tid`, the customer never saw a QR: wait out its ~60 s validity and start a new transaction.
   - If `response_type_id` is `99012` → go to step 2 (UPI Cash Withdrawal Status). QR issued — wait `status_check_start_in` seconds, then poll.
   - If `response_type_id` is `99014` → the flow is complete. Initiation failed — stop, do not dispense. Log and show `data.description`.
   - If `response_type_id` is `99015` → the flow is complete. Invalid amount — stop, fix the amount; nothing to poll.
   - If `response_type_id` is `99016` → the flow is complete. Not enabled for this retailer — stop; a provisioning task, retrying won't help.
2. `POST` **[UPI Cash Withdrawal Status](https://eps.eko.in/docs/upi-cash-withdrawal-status.md)** — Poll by `tid` every `status_check_gap` seconds, at most `status_check_attempts` times. Compare `data.tx_status` to the string "0"; anything else — "1", "2", an unknown value, a timeout — is NOT paid. Pending `response_type_id` (99019) after the last scheduled poll: stop, treat as not paid, re-query once after a few minutes, and escalate to Eko support with `tid` if still pending after ~30 minutes.
   - If `response_type_id` is `99013` → the flow is complete. Paid — dispense the cash and store `bank_ref_num`.
   - If `response_type_id` is `99018` → the flow is complete. Failed — nothing debited; do not dispense.

## Notes

- Call the steps in the order shown above; each links to its full API reference.
- Branch on the exact field each step names above: `response_type_id` says which response shape came back (the usual routing key), while `status` is the envelope's success flag — `0` is success, anything else is a failure.
- All requests are signed; see [How Auth Works](https://eps.eko.in/docs/how-auth-works).
