Recharge Overview
Place real-money mobile recharges — prepaid top-ups and postpaid bill payments — directly from your pre-funded wallet
Recharge Overview
The Recharge API places real-money mobile recharges on Indian phone numbers: prepaid top-ups and postpaid bill payments. The amount is debited from your pre-funded Starship wallet, and the recharge is sent to the operator immediately.
A recharge is irreversible from your side once the operator confirms it. There is no client cancel endpoint. Reversals happen only when the operator itself returns the money, and are handled by Starship support — never assume one is available. Treat every POST /api/v1/recharges call as final, and read Idempotency before you build retries.
How recharge differs from voucher orders
This is the single most important thing to understand before integrating, because it is the opposite of how Orders behave.
| Voucher orders | Recharge | |
|---|---|---|
| Fulfilment source | Inventory first, vendor API only as an admin-approved fallback | No inventory — the vendor call is the product |
| Vendor write API | Never called automatically for most vendors; an inventory miss parks the order PENDING | Always called automatically on submit |
| Reversibility | A parked order can be cancelled before fulfilment | Irreversible once the operator confirms |
| Your exposure ceiling | Wallet balance | Wallet balance |
Recharge auto-fulfils by design. There is no inventory to check and no admin gate on the individual transaction. The controls that replace that gate are the guards and the pre-funded wallet, which caps your total exposure to float you have already transferred to us.
Availability
Recharge is off by default for every client. Before your API calls will succeed, Starship must enable recharge for your account, and enable the API channel specifically. Contact your account manager to be switched on.
Two consequences for your integration:
- A
403from these endpoints is usually a configuration answer, not a bad request. See the error table. - Sandbox enablement and production enablement are separate. Being live in sandbox does not mean you are live in production.
Scope of v1
| Aspect | v1 behaviour |
|---|---|
| Country | India only. country_code defaults to IN when omitted |
| Currency | INR |
| Amount | Whole rupees only. 10.50 is rejected, never rounded |
| Operator | You name the operator; we never infer it from the number |
| Recharge kinds | Prepaid top-up, postpaid bill payment, and "special" recharges (BSNL / MTNL only) |
Why you must name the operator
Mobile Number Portability means a number's series no longer identifies its operator, and our vendor exposes no detect endpoint. So operator_id is required on every submit and is validated against our catalog. Fetch valid ids from GET /api/v1/recharge/operators.
The five endpoints
| Method | Endpoint | Purpose |
|---|---|---|
| GET | /api/v1/recharge/operators | The operator catalog — get a valid operator_id |
| POST | /api/v1/recharge/charges | Price preview: face, discount, payable. Places nothing |
| POST | /api/v1/recharges | Places a real recharge. Idempotency-Key required |
| GET | /api/v1/recharges | List your recharges, newest first |
| GET | /api/v1/recharges/:id | Fetch one — the endpoint you poll after a 202 |
Typical integration flow
1. GET /api/v1/recharge/operators → cache the operator list
2. POST /api/v1/recharge/charges → show the user what it costs (optional)
3. POST /api/v1/recharges → place it (Idempotency-Key required)
├── 200 + status SUCCESS → done, operator confirmed
├── 200 + status FAILED → wallet already credited back
└── 202 + status PROCESSING → not settled yet, go to 4
4. GET /api/v1/recharges/:id → poll until status leaves PROCESSINGStatus lifecycle
PROCESSING ──→ SUCCESS (operator confirmed — final, irreversible)
│
├───────→ FAILED (wallet credited back — final)
│
└───────→ REVERSED (settled then reversed — wallet credited back)Status values
| Status | Meaning | Final | Wallet |
|---|---|---|---|
PROCESSING | Accepted and debited; the operator has not given a verdict yet | No | Debited |
SUCCESS | The operator confirmed the recharge | Yes | Debited |
FAILED | The recharge did not happen | Yes | Credited back |
REVERSED | Settled, then reversed afterwards | Yes | Credited back |
PROCESSING is not a failure. It is a receipt. We hold the recharge and settle it from the vendor's push or our own status poll. The wallet stays debited until the vendor tells us otherwise. Poll GET /api/v1/recharges/:id — do not resubmit.
Some historical rows carry legacy status values (PENDING, DELIVERED, RECHARGED, CANCELLED). The API normalises these onto the four canonical values above, and the status query filter accepts the canonical value and matches the legacy rows too.
Sub-status
Every recharge also carries a sub_status giving finer detail within the status. Treat it as diagnostic, not as control flow — branch on status.
sub_status | Typical meaning |
|---|---|
INITIAL | Created, not yet sent to the vendor |
VENDOR_SUBMITTED | Sent to the vendor |
VENDOR_PENDING | The vendor has it and is awaiting the operator |
OPERATOR_CONFIRMED | The operator confirmed |
REVERSED | Reversed after settlement |
REFUNDED | The wallet has been credited back |
NEEDS_REVIEW | Held for manual review by Starship operations |
Access guards
Every submit runs a chain of guards before your wallet is touched. Each failure maps to a distinct HTTP status so you can tell "try again later" from "this will never work".
| Guard | Scope | Failure |
|---|---|---|
| Global kill-switch | All clients | 503 |
| Client enablement | Your account | 403 |
| Client pause | Your account, temporary | 503 |
| API channel toggle | Your account | 403 |
| Recharge kind toggle (prepaid / postpaid) | Your account | 403 |
| Operator overlay | Your account + one operator | 403 |
| Duplicate guard | Your account + number + amount | 409 |
| Wallet balance | Your wallet | 400 |
The wallet balance check is the only amount gate. There are no per-transaction caps, no daily spend limits and no velocity limits, because the wallet is pre-funded and is therefore its own ceiling.
The duplicate guard
A repeat of the same (mobile_number, amount) from your account inside a configurable window is refused with 409. The window is a Starship-side setting, not a value you send.
That guard exists so a network retry storm cannot turn one intent into two irreversible recharges. A genuine repeat top-up is legitimate, so the escape hatch is "force": true — see Submit a recharge.
Pricing
Recharge pricing is a per-client discount off face value:
payable = face - (face * discount_pct / 100)Your discount_pct is resolved per client and per operator and can change without notice, so do not hardcode it. Call POST /api/v1/recharge/charges when you need to show a price, and read the authoritative payable off the submit response.
If Starship has no discount configured, the rate is 0 and you pay face value — pricing fails safe rather than guessing.
Webhooks
Recharge does not emit webhooks today. The Webhooks API covers order events. There is no recharge event type you can subscribe to, so PROCESSING must be resolved by polling GET /api/v1/recharges/:id.
Rate limits
Recharge endpoints have no dedicated rate-limit rule. They fall under the general /api/v1/ limit of 1000 requests per hour, keyed by API key. Your account may carry a different configured limit — see Rate Limits.
When polling a PROCESSING recharge, back off rather than tight-looping: a poll every few seconds for the first minute, then progressively slower, will comfortably stay inside the limit.
Next steps
- Operators API — get a valid
operator_id - Charges API — preview the price
- Submit a recharge — place it
- List and get recharges — poll and reconcile