Recharge Charges API
Quote face, discount and payable for a prospective recharge without placing it — the pre-submit price preview
Recharge Charges API
Prices a recharge before you commit to it. Given an operator and an amount, it returns what the top-up is worth, the discount your client is entitled to, and exactly what would leave your wallet.
Nothing is placed, nothing is reserved and no money moves. This is a quote endpoint.
Endpoint
POST /api/v1/recharge/chargesAuthentication: API Key + Secret required
It is a POST rather than a GET because pricing is per-client and dynamic: the answer depends on who is asking, so it is neither cacheable nor safely expressible as a shareable URL. Responses are never cached.
Request Headers
X-API-Key: sk_7Fq2XmR9vTb4NcZ1yWd6Ke
X-API-Secret: your-secret-here
Content-Type: application/json| Header | Required | Description |
|---|---|---|
X-API-Key | Yes | Your API key |
X-API-Secret | Yes | Your API secret |
Content-Type | Yes | Must be application/json |
No Idempotency-Key is needed. This endpoint changes nothing, so it is safe to call repeatedly. Only POST /api/v1/recharges requires an idempotency key.
Request Body
{
"operator_id": 1,
"amount": 199
}| Field | Type | Required | Validation | Description |
|---|---|---|---|---|
operator_id | number | Yes | Must exist and be active | From GET /api/v1/recharge/operators |
amount | number | string | Yes | Whole rupees, greater than zero | The face value of the prospective recharge |
Amount is exact, never a float
amount accepts a JSON number (199) or a string ("199"). Both are parsed as an exact decimal — money never passes through floating point on the way in.
It must be a whole rupee. 199.50 is rejected with 400, not rounded and not truncated. The reason is upstream: the recharge vendor truncates fractional input, so accepting 199.50 would debit your wallet for ₹199.50 and credit the phone with ₹199. Rather than let the amount change silently under you, the API refuses it.
This endpoint does not check the recharge type. It takes no is_postpaid or is_special field, so it cannot tell you whether the operator will accept the recharge you have in mind — only what it would cost. A quote succeeding is not a guarantee that the matching submit will. Capability checks (supports_prepaid, supports_postpaid, supports_special), circle requirements, and per-client operator blocks are all enforced at submit.
Response
Success Response
Status Code: 200 OK
{
"face": 199.00,
"discount_pct": 2.50,
"discount": 4.98,
"payable": 194.02
}Response Fields
| Field | Type | Description |
|---|---|---|
face | number | The recharge amount — what reaches the phone. Echoes your amount. |
discount_pct | number | The discount percentage resolved for your client and this operator |
discount | number | face × discount_pct ÷ 100, rounded to 2 decimal places |
payable | number | face − discount — what your wallet would be debited |
All four are returned with two decimal places.
Show payable to your user, not face. face is what the phone receives; payable is what you are charged. The gap between them is your margin.
Note the asymmetry: face is always a whole rupee, but payable legitimately carries paise. A 2.5% discount on ₹199 is ₹4.98, leaving ₹194.02 payable.
How your discount is resolved
The percentage comes from the first of these that matches — a three-tier precedence:
| Tier | Rule | Beats |
|---|---|---|
| 1 | A discount configured for your client and this specific operator | Everything |
| 2 | Your client's default discount, applying to all operators | Tier 3 |
| 3 | The platform default discount | — |
A tier-1 rule always wins regardless of how the rules are ordered internally. If no rule matches at any tier and no platform default is configured, the discount is 0 and payable equals face — a missing configuration never invents a discount.
Because tier 1 is per-operator, the same amount can quote differently across operators. Quote per operator rather than caching one percentage and applying it everywhere.
Should you call this before every submit?
It is optional. POST /api/v1/recharges re-prices server-side and debits the authoritative amount, so skipping the quote never risks being charged something different from what the pricing rules say.
Call it when you need to show a price — a confirmation screen, a basket total, a margin calculation. Skip it in a server-to-server flow that submits without user confirmation, and save the rate-limit budget.
Errors
| Status | Code | Message | Cause |
|---|---|---|---|
400 | E_VALIDATION_FAILURE | invalid request body | Body is not valid JSON, or a field has the wrong type |
400 | E_VALIDATION_FAILURE | operator_id is required | operator_id missing or 0 |
400 | E_VALIDATION_FAILURE | amount must be greater than zero | amount is zero or negative |
400 | E_VALIDATION_FAILURE | amount must be a whole rupee | amount has a fractional part |
400 | E_VALIDATION_FAILURE | unknown operator_id | No such operator, or the operator is inactive |
401 | E_UNAUTHORIZED_ACCESS | — | Missing, invalid or non-whitelisted credentials |
500 | INTERNAL_SERVER_ERROR | Failed to calculate recharge charges | Pricing lookup failed, or a configured discount percentage is outside [0,100] |
Errors use the standard envelope:
{
"error": {
"name": "ValidationException",
"code": "E_VALIDATION_FAILURE",
"message": "amount must be a whole rupee"
}
}Branch on error.code, never on error.message — see Error Codes.
Examples
# Quote a 199 rupee top-up
curl -X POST "{{host}}/api/v1/recharge/charges" \
-H "X-API-Key: sk_7Fq2XmR9vTb4NcZ1yWd6Ke" \
-H "X-API-Secret: your-secret-here" \
-H "Content-Type: application/json" \
-d '{
"operator_id": 1,
"amount": 199
}'
# Amount as a string — parsed identically
curl -X POST "{{host}}/api/v1/recharge/charges" \
-H "X-API-Key: sk_7Fq2XmR9vTb4NcZ1yWd6Ke" \
-H "X-API-Secret: your-secret-here" \
-H "Content-Type: application/json" \
-d '{
"operator_id": 1,
"amount": "199"
}'
# Rejected — fractional rupees
curl -X POST "{{host}}/api/v1/recharge/charges" \
-H "X-API-Key: sk_7Fq2XmR9vTb4NcZ1yWd6Ke" \
-H "X-API-Secret: your-secret-here" \
-H "Content-Type: application/json" \
-d '{
"operator_id": 1,
"amount": 199.50
}'
# => 400 { "error": { "code": "E_VALIDATION_FAILURE", "message": "amount must be a whole rupee" } }Next steps
- Submit a Recharge — place the recharge you just quoted
- Recharge Operators API — where
operator_idcomes from