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

# AgentPay MCP Tool Reference

> Arguments and example responses for all 17 AgentPay MCP tools, plus the server's endpoints, result format, error types and request headers.

This page lists every tool the AgentPay MCP (Model Context Protocol) server provides, with its arguments and an example response. For the order in which your agent calls them, see the [AgentPay MCP integration guide](https://www.cashfree.com/docs/tools-ai/agentpay-mcp/integration-guide.md).

## Tools at a glance

AgentPay provides 17 tools, grouped by the step of the [payment flow](https://www.cashfree.com/docs/tools-ai/agentpay-mcp/integration-guide.md#pay-a-bill-step-by-step) they belong to. Tools that work with the customer's wallet need the `access_token` from the consent step:

| Step | Tool | What it does | Needs `access_token`? |
| - | - | - | - |
| Find the biller | `list_biller_categories` | Lists bill categories, such as Electricity. | No |
| Find the biller | `list_billers` | Finds billers and tells you what details they need. | No |
| Fetch the bill | `request_bill_fetch` | Starts fetching or validating a bill. | No |
| Fetch the bill | `poll_bill_fetch` | Checks whether the bill has arrived. | No |
| Get consent | `create_mandate_session` | Creates the consent link for the customer. | No |
| Get consent | `get_mandate_session` | Checks whether the customer has approved, and returns tokens. | No |
| Get consent | `refresh_access_token` | Gets a new `access_token`. | No |
| Get consent | `revoke_consent` | Ends the customer's consent. | `access_token` or `refresh_token` |
| Check the wallet balance | `get_wallet_balance` | Checks the wallet balance and status. | Yes |
| Check the wallet balance | `topup_wallet` | Creates a link for the customer to add money. | Yes |
| Check the wallet balance | `get_topup_status` | Checks whether the top-up is paid. | Yes |
| Debit the wallet | `wallet_pay` | Takes money from the wallet. | Yes |
| Debit the wallet | `get_pay_status` | Confirms the debit and returns the `transaction_id`. | Yes |
| Pay the biller | `request_bill_payment` | Tells the biller the bill is paid. | No |
| Pay the biller | `poll_bill_payment` | Checks the result and returns the `utr`. | No |
| Refund | `refund_payment` | Returns a debit to the wallet. | Optional |
| Refund | `get_refund_status` | Checks the refund status. | Optional |

Cashfree may add response fields over time, so read the fields you need and ignore the rest. For the format of a failed result, see [Technical details](#technical-details).

## Find the biller

These tools identify the biller and the details the customer must give.

### list\_biller\_categories

Lists all bill categories. Use it to map what the customer says, such as "my electricity bill", to a category name. Categories rarely change, so you can cache this list.

**Arguments:** None. Call it with `{}`.

```json Response theme={"dark"}
{
  "biller_categories": [
    { "biller_category_name": "Electricity" },
    { "biller_category_name": "Water" },
    { "biller_category_name": "Mobile Postpaid" }
  ]
}
```

### list\_billers

Finds billers in one or more categories and tells you what each one needs.

| Argument | Type | Required | Description |
| - | - | - | - |
| `biller_category_name` | array of strings | Yes | One or more categories, for example `["Electricity"]`. Don't pass Credit Card or Loan Repayment. |
| `biller_name` | string | No | Part of the biller's name, case-insensitive. Strongly recommended, because unfiltered results can be very large. |
| `limit` | integer | No | Maximum billers to return. Default is 50. |

```json Response theme={"dark"}
{
  "status": "OK",
  "data": [
    {
      "biller_id": "BESCOM000KAR01",
      "biller_name": "Bangalore Electricity Supply Co. Ltd (BESCOM)",
      "biller_alias_name": "BESCOM",
      "biller_category_name": "Electricity",
      "biller_coverage": "IND-KAR",
      "fetch_requirement": "MANDATORY",
      "support_bill_validation": "NOT_SUPPORTED",
      "payment_amount_exactness": "Exact and above",
      "biller_customer_params": [
        {
          "param_name": "Customer ID / Account ID",
          "data_type": "NUMERIC",
          "optional": false,
          "min_length": 1,
          "max_length": 10,
          "regex": "^[0-9]{1,7}$|^[0-9]{10}$"
        }
      ],
      "status": "ACTIVE"
    }
  ],
  "total_matched": 1
}
```

The key fields to read are:

* `biller_id`: pass it to the fetch, debit and payment tools.
* `biller_customer_params`: the details to ask the customer for. Use each `param_name` exactly as written, and check values against `regex`.
* `fetch_requirement` and `support_bill_validation`: decide whether to fetch, validate or pay directly (see [Choose a payment flow](https://www.cashfree.com/docs/tools-ai/agentpay-mcp/integration-guide.md#choose-a-payment-flow)).
* `payment_amount_exactness`: whether the customer must pay the exact bill amount, or can pay more or less.
* `status`: prefer billers that are `ACTIVE`.
* `truncated` and `note`: present when more billers matched than `limit`. Narrow the search or raise `limit`.

## Fetch the bill

These tools fetch the amount due, or validate the customer's details for a validate-first biller.

### request\_bill\_fetch

Starts fetching a customer's bill and returns a `ref_id`. The bill arrives a moment later through `poll_bill_fetch`. For a validate-first biller, it validates the customer's details instead. Don't use it for direct-payment billers.

| Argument | Type | Required | Description |
| - | - | - | - |
| `biller_id` | string | Yes | From `list_billers`. |
| `customer_mobile` | string | Yes | The customer's 10-digit mobile number. |
| `input_params` | array of objects | Yes | The details the biller needs, as `{ "param_name", "param_value" }` pairs. `param_name` must match `biller_customer_params` exactly, including case and spaces. Fill any Mobile Number field with `customer_mobile`. |

```json Response theme={"dark"}
{
  "status": "ACCEPTED",
  "data": { "ref_id": "4fd9fb282bf846a685a4301d15563031223", "status": "PROCESSING", "flow": "FETCH_AND_PAY" }
}
```

Save the `ref_id`. You use it to poll the bill, debit the wallet (as `reference_id`) and pay the biller (as `bill_fetch_ref_id`). `flow` is `FETCH_AND_PAY` for a normal bill or `VALIDATE_AND_PAY` when Cashfree only validates the customer's details.

A `ref_id` is valid for 15 minutes. If it's older when you're ready to debit the wallet, call `request_bill_fetch` again. If it expires after `wallet_pay` but before the bill payment reaches the biller, refund the debit once it's 15 minutes old, then start again with a fresh fetch.

### poll\_bill\_fetch

Checks whether the bill has arrived. Call it every 2 to 3 seconds.

| Argument | Type | Required | Description |
| - | - | - | - |
| `ref_id` | string | Yes | From `request_bill_fetch`. |

```json Response theme={"dark"}
{
  "status": "OK",
  "data": {
    "bill_fetch_response": { "ref_id": "4fd9fb282bf846a685a4301d15563031223", "response_code": "000", "response_reason": "Successful" },
    "bill_details": {
      "customer_params": { "tag": [ { "name": "Customer ID / Account ID", "value": "1234567890" } ] }
    },
    "biller_response": {
      "customer_name": "Rahul Sharma",
      "amount": "350.00",
      "cust_conv_fee": "0.00",
      "due_date": "2026-10-25",
      "bill_date": "2026-10-01",
      "bill_number": "INV-889201",
      "bill_period": "SEP-2026"
    },
    "additional_info": null
  }
}
```

`response_code` is `PENDING` while the bill is on its way, `000` on success, or another code if the fetch failed. Show the customer the name, amount and due date from `biller_response`. Amounts are strings in rupees, and dates use `YYYY-MM-DD`.

For a validate-first biller, a `000` response has `bill_fetch_response` and `additional_info` but no `biller_response` or `bill_details`. That means the customer's details are valid, but there's no bill amount, so ask the customer how much to pay.

You don't need to copy anything from this response into later calls. `request_bill_payment` reads the bill back from Cashfree using the `ref_id`.

## Get consent

These tools get the customer's one-time approval and manage their tokens.

### create\_mandate\_session

Creates the consent link. The customer opens it, logs in with a one-time password (OTP), approves your agent, and can top up their wallet.

| Argument | Type | Required | Description |
| - | - | - | - |
| `phone` | string | Yes | The customer's 10-digit mobile number. Use the same one as the bill fetch. |
| `return_url` | string | No | HTTPS page to send the customer to afterwards. Defaults to a Cashfree thank-you page. |
| `idempotency_key` | string | No | Reuse it when retrying, so you get the same session back. |

```json Response theme={"dark"}
{
  "session_id": "57290367-7dfa-46c7-be4f-32502d85491e",
  "consent_link": "https://sandbox.cashfree.com/checkout/workflows?wt=a65976b3-..."
}
```

Send the customer the `consent_link` in plain words, for example: "To pay from your wallet, open this link, log in with the OTP and approve."

### get\_mandate\_session

Checks whether the customer has finished on the consent page.

| Argument | Type | Required | Description |
| - | - | - | - |
| `session_id` | string | Yes | From `create_mandate_session`. |

While the customer is still on the page, the response is `{ "status": "PENDING" }`. Once they approve, it looks like this:

```json Response theme={"dark"}
{
  "status": "CONFIRMED",
  "access_token": "agpa_v1.Cd2x...",
  "refresh_token": "agpr_v1.THCR...",
  "expires_in": 3553,
  "terms": {
    "agent_name": "CF Test Agent 2",
    "max_amount_per_month": 10000,
    "max_debits_per_month": 5,
    "validity_months": 6
  }
}
```

`expires_in` is the number of seconds until the `access_token` expires. `max_amount_per_month` is in rupees. If the status is `EXPIRED` or `FAILED`, stop polling and create a new session.

### refresh\_access\_token

Gets a new `access_token` when the old one expires.

| Argument | Type | Required | Description |
| - | - | - | - |
| `refresh_token` | string | Yes | From `get_mandate_session`. |

```json Response theme={"dark"}
{ "access_token": "agpa_v1....", "expires_in": 3600 }
```

This fails once the customer's consent has expired or been revoked. In that case, create a new consent session.

### revoke\_consent

Ends the customer's consent when they ask your agent to stop paying from their wallet. Every `access_token` and `refresh_token` for that consent stops working. Payments already in progress still complete, and refunds remain possible.

| Argument | Type | Required | Description |
| - | - | - | - |
| `access_token` | string | One of the two | The customer's wallet token. Used if you send both. |
| `refresh_token` | string | One of the two | From `get_mandate_session`. Use it when you don't have a valid `access_token`. |

```json Response theme={"dark"}
{ "status": "REVOKED", "revoked_at": 1762300800 }
```

You can call it again safely. A revoked consent returns `REVOKED` with the same `revoked_at`. A consent that had already expired or been declined returns its current status with no `revoked_at`. To pay for this customer again, create a new consent session.

## Check the wallet balance

These tools check the wallet balance and add money when it's short.

### get\_wallet\_balance

Checks whether the wallet can pay the bill.

| Argument | Type | Required | Description |
| - | - | - | - |
| `access_token` | string | Yes | The customer's wallet token. |

```json Response theme={"dark"}
{ "eligibility": true, "balance": 1500, "reason": "", "blocked": false, "wallet_exists": true }
```

`balance` is in rupees, so 1500 means ₹1,500. If `eligibility` is `false`, `blocked` is `true` or `wallet_exists` is `false`, read `reason` to see why.

### topup\_wallet

Creates a payment link so the customer can add money to their wallet.

| Argument | Type | Required | Description |
| - | - | - | - |
| `access_token` | string | Yes | The customer's wallet token. |
| `order_amount` | number | Yes | Amount to add in rupees, up to 2 decimal places. |
| `order_id` | string | No | Your ID for the top-up (letters, digits, `-` and `_`). Retrying with the same ID and amount safely returns the same order. Leave it out to get a generated ID. |
| `order_note` | string | No | A note on the order. |
| `return_url` | string | No | HTTPS page to send the customer to after paying. |
| `payment_method` | string | No | `upi` or `netbanking`. Leave it out to get a hosted checkout link. Set it to start a UPI or net banking payment directly. |
| `netbanking_bank_code` | integer | With `netbanking` | The bank's net banking code, for example `3021`. |
| `idempotency_key` | string | No | Reuse it when retrying. |

```json Response theme={"dark"}
{
  "order_id": "topup-001",
  "order_amount": 500,
  "order_currency": "INR",
  "order_status": "ACTIVE",
  "payment_link": "https://sandbox.cashfree.com/pg/view/sessions/checkout/web/..."
}
```

Send the customer the `payment_link`, then check `get_topup_status`.

### get\_topup\_status

Checks whether the customer has paid the top-up.

| Argument | Type | Required | Description |
| - | - | - | - |
| `order_id` | string | Yes | From `topup_wallet`. |
| `access_token` | string | Yes | The customer's wallet token. |

The response looks like the `topup_wallet` response. `order_status` is `ACTIVE` until the customer pays, then `PAID`. Check `get_wallet_balance` before you debit.

## Debit the wallet

These tools take money from the wallet and confirm the debit.

### wallet\_pay

Takes money from the customer's wallet for a bill. This only debits the wallet. It doesn't pay the biller.

| Argument | Type | Required | Description |
| - | - | - | - |
| `order_id` | string | Yes | A new unique ID for this debit, up to 100 characters. It must be unique across all your customers. |
| `reference_id` | string | One of the two | The `ref_id` from `request_bill_fetch`, for fetched and validated bills. Up to 128 characters. |
| `biller_id` | string | One of the two | For direct-payment billers only, where `fetch_requirement` and `support_bill_validation` are both `NOT_SUPPORTED`. Up to 64 characters. |
| `order_amount` | number | Yes | Amount in rupees, up to 2 decimal places, for example `350`. Use the exact amount you will pay the biller. |
| `customer_id` | string | No | Your own reference for the customer. The wallet is chosen by `access_token`, not by this value. |
| `access_token` | string | Yes | The customer's wallet token. |
| `idempotency_key` | string | No | Reuse it when retrying the same debit. |

```json Response theme={"dark"}
{ "status": "ACCEPTED", "order_id": "AP-9999999999-1761120000", "reference_id": "4fd9fb282bf846a685a4301d15563031223" }
```

For a direct payment, the response has `biller_id` instead of `reference_id`. `ACCEPTED` means the request was received, not that the money moved. Always call `get_pay_status` next.

Cashfree refuses the debit in the following cases:

| Error | Cause |
| - | - |
| `agent_pay_bill_fetch_required` | You sent `biller_id` for a biller that supports bill fetch or validation. |
| `invalid_order_amount` | For a fetched bill, the amount doesn't follow the biller's `payment_amount_exactness`. For any bill, the amount is outside the biller's wallet payment limits or has more than 2 decimal places. |
| `wallet_not_supported_by_biller` | The biller doesn't accept wallet payments. |
| `order_id_conflict` | You already used this `order_id` for a different payment. |
| `monthly_debit_limit_exceeded` | The debit would go over the customer's monthly limits. |

Cashfree also refuses the debit if the category is Credit Card or Loan Repayment, or if the balance is too low.

### get\_pay\_status

Confirms the debit and gives you the `transaction_id` you need to pay the biller.

| Argument | Type | Required | Description |
| - | - | - | - |
| `order_id` | string | Yes | The `order_id` you used in `wallet_pay`. |
| `access_token` | string | Yes | The customer's wallet token. |

```json Response theme={"dark"}
{ "order_id": "AP-9999999999-1761120000", "txstatus": "SUCCESS", "transaction_id": "5114917215931", "order_amount": 350 }
```

`txstatus` is `SUCCESS` when the wallet was debited. `INITIATED` or `PENDING` means check again. `FAILED` means no money moved, so don't pay the biller.

## Pay the biller

These tools tell the biller the bill is paid and return the receipt.

### request\_bill\_payment

Tells the biller the bill is paid, using the wallet debit as proof. The result arrives through `poll_bill_payment`. The server adds the payment mode (Wallet) and the BBPS agent and device details itself.

| Argument | Type | Required | Description |
| - | - | - | - |
| `pg_reference_id` | string | Yes | The `transaction_id` from `get_pay_status`. |
| `biller_id` | string | Yes | The same `biller_id` you used for the bill fetch or the debit. |
| `customer_mobile` | string | Yes | The same mobile number used for the bill fetch. |
| `bill_fetch_ref_id` | string | Yes, except direct payments | The `ref_id` from `request_bill_fetch`. |
| `customer_params` | array of objects | Validated bills and direct payments | The customer's details as `{ "param_name", "param_value" }` pairs, the same as `request_bill_fetch`'s `input_params`. Ignored for fetched bills. |
| `amount` | number | Validated bills and direct payments | The amount paid in rupees. Must equal the `wallet_pay` `order_amount`. Ignored for fetched bills. |
| `shortfall_amount` | string | No | The part of the bill the wallet didn't cover. Default `"0.00"`, which means the wallet paid in full. |

What you send depends on the [payment flow](https://www.cashfree.com/docs/tools-ai/agentpay-mcp/integration-guide.md#choose-a-payment-flow):

* **Fetched bill:** send `bill_fetch_ref_id`. The server reads the customer details, bill and amount back from the fetch, so they always match what the biller sent.
* **Validated bill:** send `bill_fetch_ref_id`, `customer_params` and `amount`, because a validation has no bill to read back.
* **Direct payment:** leave out `bill_fetch_ref_id`, and send `customer_params` and `amount`.

```json Response theme={"dark"}
{
  "status": "PENDING",
  "transaction_ref_id": "7f3a1c2e9b0d4e5f8a6c1b2d3e4f5061",
  "message": "Bill payment request accepted, poll for result"
}
```

Save the `transaction_ref_id` and pass it to `poll_bill_payment`.

### poll\_bill\_payment

Checks the final result of the bill payment. Call it until the status is `SUCCESS` or `FAILURE`.

| Argument | Type | Required | Description |
| - | - | - | - |
| `transaction_ref_id` | string | Yes | From `request_bill_payment`. |
| `bill_fetch_ref_id` | string | Yes, except direct payments | The `ref_id` from `request_bill_fetch`. |

```json Response theme={"dark"}
{
  "status": "SUCCESS",
  "transaction_ref_id": "7f3a1c2e9b0d4e5f8a6c1b2d3e4f5061",
  "utr": "309012345678",
  "amount": "350.00",
  "settled_at": "2026-10-22T12:10:45Z"
}
```

Give the customer the `utr` as their receipt. On `FAILURE`, the response also includes `error_code` and `error_message`.

## Refund

These tools return money to the customer's wallet. They find the debit by your `order_id`, so they work even after the customer's consent expires or is revoked.

### refund\_payment

Returns a wallet debit to the customer. You can refund a debit whose `txstatus` is `SUCCESS` when its bill payment failed, or when the bill payment never reached the biller and the debit is at least 15 minutes old.

| Argument | Type | Required | Description |
| - | - | - | - |
| `order_id` | string | Yes | The `wallet_pay` debit to refund. |
| `refund_id` | string | Yes | Your unique ID for this refund, up to 28 characters. |
| `refund_amount` | number | Yes | Amount in rupees, no more than the debit. |
| `refund_note` | string | No | A note, up to 100 characters. |
| `access_token` | string | No | The customer's wallet token. Send it when you have one. |
| `idempotency_key` | string | No | Reuse it when retrying the same refund. |

```json Response theme={"dark"}
{ "refund_id": "refund-001", "order_id": "AP-9999999999-1761120000", "refund_amount": 350, "refund_status": "PENDING" }
```

Cashfree refuses the refund with `bill_already_paid` if the biller received the payment, or `bill_payment_not_terminal` while the bill payment is still in progress.

### get\_refund\_status

Checks whether the refund has completed.

| Argument | Type | Required | Description |
| - | - | - | - |
| `order_id` | string | Yes | The refunded `wallet_pay` debit. |
| `refund_id` | string | Yes | The `refund_id` you used in `refund_payment`. |
| `access_token` | string | No | The customer's wallet token. Send it when you have one. |

The response looks like the `refund_payment` response. `refund_status` changes from `PENDING` to `SUCCESS` when the money is back in the wallet.

## Technical details

Most integrations don't need this section. It's here for when you're debugging or building a custom MCP client.

### Server endpoints and protocol

The server uses the MCP Streamable HTTP transport and is stateless:

| Endpoint | Behaviour |
| - | - |
| `POST /mcp` | All MCP traffic (`initialize`, `tools/list`, `tools/call`, `resources/list`, `resources/read`). |
| `GET /mcp`, `DELETE /mcp` | Returns `405 Method not allowed`, because the server keeps no sessions. |
| `GET /healthz` | Returns `{"status":"ok"}`, with no authentication. |

The Cashfree API version is `2025-01-01`, set by the server. Each Cashfree call times out after 30 seconds.

The server also exposes a flow guide that agents can read for context, at `docs://agent-pay-bbps-flow` (`text/markdown`):

```json Request theme={"dark"}
{ "jsonrpc": "2.0", "id": 2, "method": "resources/read", "params": { "uri": "docs://agent-pay-bbps-flow" } }
```

### Tool result format

A successful tool result contains the Cashfree response as JSON text. Parse `content[0].text` as JSON:

```json Successful result theme={"dark"}
{
  "jsonrpc": "2.0",
  "id": 7,
  "result": {
    "content": [
      { "type": "text", "text": "{\n  \"status\": \"OK\",\n  \"data\": { ... }\n}" }
    ]
  }
}
```

A failed result has `isError: true` and a message with the HTTP status, method, path and Cashfree's error:

```json Failed result theme={"dark"}
{
  "result": {
    "isError": true,
    "content": [
      {
        "type": "text",
        "text": "Error executing tool 'wallet_pay': Cashfree API error 400 for POST /pg/agentpay/wallet/pay: {\"message\":\"this debit exceeds the monthly debit count limit\",\"code\":\"monthly_debit_limit_exceeded\",\"type\":\"invalid_request_error\"}"
      }
    ]
  }
}
```

The server converts any integer with 16 or more digits to a string, so long IDs such as `transaction_id` are never rounded.

### Error types

Errors come from the following places:

| Source | How it shows up |
| - | - |
| Missing or malformed `Authorization` header | HTTP 401 from the Cashfree gateway, before the request reaches the server: `{ "message": "authentication Failed", "code": "request_failed", "type": "authentication_error" }` |
| Invalid JSON | HTTP 400 with JSON-RPC error `-32700` |
| Unexpected server failure | HTTP 500 with JSON-RPC error `-32603` |
| Invalid or missing tool arguments | A tool error with a plain message, such as `input_params is required: ask the customer for their bill identifier.` |
| Cashfree rejected the request | `isError: true` with `Cashfree API error <status> for <METHOD> <path>: <body>` |
| Cashfree slow or unreachable | `isError: true` with `Cashfree API timed out after 30000ms ...` or `Cashfree API request failed ...` |
| Business result | The tool succeeds, but the response reports a failure, such as `txstatus: FAILED` or a bill payment `FAILURE` |

### Headers the server sends to Cashfree

The server forwards your API key and the tool arguments to Cashfree as the following headers. For how your API key is handled, see [Security](https://www.cashfree.com/docs/tools-ai/agentpay-mcp/integration-guide.md#security).

| Header | Value | Sent on |
| - | - | - |
| `x-client-api-key` | Your API key | All calls |
| `x-api-version` | `2025-01-01` | All calls |
| `x-access-token` | The `access_token` argument | Wallet tools, and `revoke_consent` and the refund tools when you pass it |
| `x-idempotency-key` | The `idempotency_key` argument, when passed | `create_mandate_session`, `topup_wallet`, `wallet_pay`, `refund_payment` |

The server also adds the Bharat Bill Payment System (BBPS) agent ID, initiating channel, IP and MAC to every bill fetch and bill payment. Your agent never sends these values.

### Instructions the server gives your agent

When your agent connects, the server returns `instructions` for the model. In short, they tell the model to:

* Never ask the customer for tokens, sessions or mandates.
* Reuse an `access_token` from earlier in the conversation, or start a consent session straight away.
* Talk to the customer only about the bill, amount, due date and payment result, never about API keys, IDs, tokens or API calls.
* On failure, say the bill couldn't be fetched or paid, and offer to try again.

Related topics

<ul>
  <li>[AgentPay MCP Integration Guide](https://www.cashfree.com/docs/tools-ai/agentpay-mcp/integration-guide.md)</li>
  <li>[Cashfree MCP Server](https://www.cashfree.com/docs/tools-ai/mcp-server.md)</li>
</ul>


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