Starship Rewards API
Recharge

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 ordersRecharge
Fulfilment sourceInventory first, vendor API only as an admin-approved fallbackNo inventory — the vendor call is the product
Vendor write APINever called automatically for most vendors; an inventory miss parks the order PENDINGAlways called automatically on submit
ReversibilityA parked order can be cancelled before fulfilmentIrreversible once the operator confirms
Your exposure ceilingWallet balanceWallet 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 403 from 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

Aspectv1 behaviour
CountryIndia only. country_code defaults to IN when omitted
CurrencyINR
AmountWhole rupees only. 10.50 is rejected, never rounded
OperatorYou name the operator; we never infer it from the number
Recharge kindsPrepaid 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

MethodEndpointPurpose
GET/api/v1/recharge/operatorsThe operator catalog — get a valid operator_id
POST/api/v1/recharge/chargesPrice preview: face, discount, payable. Places nothing
POST/api/v1/rechargesPlaces a real recharge. Idempotency-Key required
GET/api/v1/rechargesList your recharges, newest first
GET/api/v1/recharges/:idFetch 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 PROCESSING

Status lifecycle

PROCESSING ──→ SUCCESS      (operator confirmed — final, irreversible)

     ├───────→ FAILED       (wallet credited back — final)

     └───────→ REVERSED     (settled then reversed — wallet credited back)

Status values

StatusMeaningFinalWallet
PROCESSINGAccepted and debited; the operator has not given a verdict yetNoDebited
SUCCESSThe operator confirmed the rechargeYesDebited
FAILEDThe recharge did not happenYesCredited back
REVERSEDSettled, then reversed afterwardsYesCredited 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_statusTypical meaning
INITIALCreated, not yet sent to the vendor
VENDOR_SUBMITTEDSent to the vendor
VENDOR_PENDINGThe vendor has it and is awaiting the operator
OPERATOR_CONFIRMEDThe operator confirmed
REVERSEDReversed after settlement
REFUNDEDThe wallet has been credited back
NEEDS_REVIEWHeld 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".

GuardScopeFailure
Global kill-switchAll clients503
Client enablementYour account403
Client pauseYour account, temporary503
API channel toggleYour account403
Recharge kind toggle (prepaid / postpaid)Your account403
Operator overlayYour account + one operator403
Duplicate guardYour account + number + amount409
Wallet balanceYour wallet400

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

  1. Operators API — get a valid operator_id
  2. Charges API — preview the price
  3. Submit a recharge — place it
  4. List and get recharges — poll and reconcile