swiggy-mcp-payments
cart ready → get_payment_options → place-order (paymentMethod …) → PENDING_PAYMENT { paasId, orderId, bridgeUrl, pollingIntervalInMs, maxTimeToPollForInMs }
→ check_payment_status (long-poll ~19 s) → confirm_order → PLACED → track
Place-order tools: Food place_food_order, Instamart checkout, Dineout book_table (paid deal, after create_cart). The three payment tools have the same name and shape on every server.
Rules
get_payment_options is the only source of methods. Offer exactly what data.allMethods (or platforms.mobile/desktop.methods, cod) returns; never invent a method. Food: pass the same addressId used for get_food_cart so the picker can place directly.
- Never ask which device the user is on and never ask for a UPI ID/VPA. The picker/QR handle it; UPI Collect and saved VPAs are not surfaced (NPCI compliance).
- Pass the user's pick byte-for-byte. UPI app →
paymentMethod: "UPI" + intentApp: <method.id>. Desktop scan-QR → paymentMethod: "UPI" + generateUPIQR: true, no intentApp. Cash → paymentMethod: "Cash" (only when cod.available). Swiggy Money → paymentMethod: "SwiggyPay" only if a method with that group is returned. paymentMethod is always the group name, never an app id.
PENDING_PAYMENT is not an order. Say "Complete the payment in your UPI app — I'll confirm your order once payment succeeds." Never say placed/confirmed/successful until confirm_order succeeds (or check_payment_status reports confirmed: true). Only then use the branded message ("Swiggy order placed successfully").
- Widget hosts (Claude Desktop, ChatGPT, Cursor…): do not poll. The confirmation widget polls
check_payment_status and auto-finalizes. Call it once only if the user asks "did my payment go through?". Call confirm_order yourself only if the result says auto-confirm could not run.
- Headless clients (no widget): you own the loop. Give the user
data.bridgeUrl (opens a scan-or-tap page: QR on desktop, app button on mobile; present for both intent and QR choices — read it from data, do not parse message). Then poll check_payment_status every pollingIntervalInMs, capped at maxTimeToPollForInMs. Never tight-loop: it is a long-poll and hammering it stresses the payment cache.
- Echo identifiers; never reconstruct them.
| Server |
check_payment_status args |
confirm_order args |
| Food |
paasId, orderId, addressId, cartId, lat, lng (all echoed from place_food_order; without them the order stays pending) |
orderId, addressId, lat, lng (+cartId) — no paasId |
| Instamart |
paasId, orderId |
orderId, paasId (+transactionId) |
| Dineout |
paasId, orderId |
orderId, paasId (+transactionId) |
paasId is the payment transaction id from the place-order response — never "UPI", "PayWithQR" or an app id. If you do not have a real paasId, do not call the tool.
Branch on check_payment_status.data
status / flags |
Then |
success / paid (isTerminalSuccess) |
if confirmed is true → done; else confirm_order once |
failed (isTerminalFailure) |
do not confirm; re-show get_payment_options and place again (fresh transaction, same cart) |
cancelled |
order cancelled; any debit is refunded; do not retry on your own |
cart_changed |
not a payment failure: price/stock changed, order NOT placed; review the cart with the user, then place again |
refund-initiated |
debited and refund underway; tell the user; stop |
pending, terminal: false |
keep waiting on the cadence; at the cap call confirm_order once (backend marks it failed if still unpaid; a late success reconciles server-side) |
confirm_order is idempotent and never places an unpaid order; a duplicate call is harmless, a call after a terminal failure is pointless.
Cash
No payment leg: place with paymentMethod: "Cash" and go straight to tracking. Cash is the automatic fallback when UPI is unavailable for the cart (platforms omitted, only cod).
Swiggy Money
Announced for MCP on 4 Sept 2026: the user adds money once and the agent pays without a per-order payment step. It surfaces as a SwiggyPay group in get_payment_options when enabled for the account and cart; treat it like Cash (no pending leg) and never pass it when it is not listed.
1---2name: swiggy-mcp-payments3description: Take payment on Swiggy MCP — the shared Payment stage (get_payment_options → place-order → check_payment_status → confirm_order) for Food, Instamart and Dineout, with UPI app intent, scan-QR, Cash and Swiggy Money, in both widget and headless clients. Use whenever an order or paid booking must be paid for, a place-order tool returned PENDING_PAYMENT, or the user asks about payment status. Assumes the swiggy-mcp skill.4license: MIT5---67# swiggy-mcp-payments89```10cart ready → get_payment_options → place-order (paymentMethod …) → PENDING_PAYMENT { paasId, orderId, bridgeUrl, pollingIntervalInMs, maxTimeToPollForInMs }11 → check_payment_status (long-poll ~19 s) → confirm_order → PLACED → track12```1314Place-order tools: Food `place_food_order`, Instamart `checkout`, Dineout `book_table` (paid deal, after `create_cart`). The three payment tools have the same name and shape on every server.1516## Rules17181. **`get_payment_options` is the only source of methods.** Offer exactly what `data.allMethods` (or `platforms.mobile/desktop.methods`, `cod`) returns; never invent a method. Food: pass the same `addressId` used for `get_food_cart` so the picker can place directly.192. **Never ask which device the user is on and never ask for a UPI ID/VPA.** The picker/QR handle it; UPI Collect and saved VPAs are not surfaced (NPCI compliance).203. **Pass the user's pick byte-for-byte.** UPI app → `paymentMethod: "UPI"` + `intentApp: <method.id>`. Desktop scan-QR → `paymentMethod: "UPI"` + `generateUPIQR: true`, no `intentApp`. Cash → `paymentMethod: "Cash"` (only when `cod.available`). Swiggy Money → `paymentMethod: "SwiggyPay"` only if a method with that group is returned. `paymentMethod` is always the group name, never an app id.214. **`PENDING_PAYMENT` is not an order.** Say "Complete the payment in your UPI app — I'll confirm your order once payment succeeds." Never say placed/confirmed/successful until `confirm_order` succeeds (or `check_payment_status` reports `confirmed: true`). Only then use the branded `message` ("Swiggy order placed successfully").225. **Widget hosts (Claude Desktop, ChatGPT, Cursor…): do not poll.** The confirmation widget polls `check_payment_status` and auto-finalizes. Call it once only if the user asks "did my payment go through?". Call `confirm_order` yourself only if the result says auto-confirm could not run.236. **Headless clients (no widget): you own the loop.** Give the user `data.bridgeUrl` (opens a scan-or-tap page: QR on desktop, app button on mobile; present for both intent and QR choices — read it from `data`, do not parse `message`). Then poll `check_payment_status` every `pollingIntervalInMs`, capped at `maxTimeToPollForInMs`. Never tight-loop: it is a long-poll and hammering it stresses the payment cache.247. **Echo identifiers; never reconstruct them.**2526| Server | `check_payment_status` args | `confirm_order` args |27| --- | --- | --- |28| Food | `paasId, orderId, addressId, cartId, lat, lng` (all echoed from `place_food_order`; without them the order stays pending) | `orderId, addressId, lat, lng` (+`cartId`) — **no `paasId`** |29| Instamart | `paasId, orderId` | `orderId, paasId` (+`transactionId`) |30| Dineout | `paasId, orderId` | `orderId, paasId` (+`transactionId`) |3132`paasId` is the payment transaction id from the place-order response — never `"UPI"`, `"PayWithQR"` or an app id. If you do not have a real `paasId`, do not call the tool.3334## Branch on `check_payment_status.data`3536| `status` / flags | Then |37| --- | --- |38| `success` / `paid` (`isTerminalSuccess`) | if `confirmed` is true → done; else `confirm_order` once |39| `failed` (`isTerminalFailure`) | **do not confirm**; re-show `get_payment_options` and place again (fresh transaction, same cart) |40| `cancelled` | order cancelled; any debit is refunded; do not retry on your own |41| `cart_changed` | not a payment failure: price/stock changed, order NOT placed; review the cart with the user, then place again |42| `refund-initiated` | debited and refund underway; tell the user; stop |43| `pending`, `terminal: false` | keep waiting on the cadence; at the cap call `confirm_order` once (backend marks it failed if still unpaid; a late success reconciles server-side) |4445`confirm_order` is idempotent and never places an unpaid order; a duplicate call is harmless, a call after a terminal failure is pointless.4647## Cash4849No payment leg: place with `paymentMethod: "Cash"` and go straight to tracking. Cash is the automatic fallback when UPI is unavailable for the cart (`platforms` omitted, only `cod`).5051## Swiggy Money5253Announced for MCP on 4 Sept 2026: the user adds money once and the agent pays without a per-order payment step. It surfaces as a `SwiggyPay` group in `get_payment_options` when enabled for the account and cart; treat it like Cash (no pending leg) and never pass it when it is not listed.