Wallet and Billing API

Run the Edesy prepaid wallet from your own admin portal - read the balance, recharge with Razorpay Checkout or a hosted payment link, confirm the recharge landed, and get wallet.low_balance and wallet.recharged webhooks.

5 min read

The Wallet and Billing API lets your own admin portal do what the wallet page does: show the balance, take a recharge, confirm it was credited, and get told when the balance runs low. You recharge either with Razorpay Checkout on your page or with a hosted payment link you redirect to or send. Two webhooks, wallet.low_balance and wallet.recharged, tell your server what happened.

Base URL https://voice-api.edesy.in/v1. Every call is made from your server with Authorization: Bearer <API key>; the key can spend your wallet, so never put it in browser code.

Facts#

Item Detail
Currency INR. The wallet holds money before GST: a Rs 500 recharge charges Rs 590 and adds Rs 500
Minimum recharge Rs 10
Recharge methods Razorpay Checkout on your page, or a hosted Razorpay payment link
Rate limit Create Recharge Order and Create Payment Link share 10 a minute per account; over it returns 429 with Retry-After
Payment link expiry 7 days by default; 16 minutes to 180 days with expire_in_minutes
Confirmation wallet.recharged webhook, or poll Get Payment until completed
Low-balance threshold Rs 100 unless agreed otherwise
Invoices A GST tax invoice for every completed recharge, as HTML or PDF

Endpoints#

Method Path Description
GET /billing Balance, this month's usage, your rates and the account state
POST /billing/create-order Create a Razorpay order for Checkout
POST /billing/verify-payment Optional: credit a Checkout payment straight away
POST /billing/payment-links Create a hosted payment link
GET /billing/payments/{id} One recharge and its status
GET /billing/transactions The wallet ledger (.csv for an export)
GET /billing/invoices Completed recharges with invoice numbers
GET /billing/payments/{id}/invoice?format=pdf Download an invoice
POST /webhooks/subscriptions Subscribe to wallet events

Show the balance#

curl https://voice-api.edesy.in/v1/billing -H "Authorization: Bearer $EDESY_KEY"

balance is what you can spend. account_state.status tells you when to prompt a recharge: ok, low_balance (below the threshold), past_due (negative balance or an unpaid number rental) or suspended. outbound_blocked says whether outbound calls are being refused.

Recharge with Checkout#

The payer stays on your page while Razorpay's payment window opens on top of it.

curl -X POST https://voice-api.edesy.in/v1/billing/create-order \
  -H "Authorization: Bearer $EDESY_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "amount": 500 }'
{ "data": { "order_id": "order_...", "payment_id": "...", "key_id": "rzp_live_...",
  "subtotal": 500, "tax_rate": 0.18, "tax_amount": 90, "total": 590, "currency": "INR" } }
  1. Your server creates the order. amount is what to credit, before GST. Add gstin to print your GSTIN on the invoice.
  2. Your page opens Razorpay Checkout with key_id, order_id and total x 100 (paise). Only order_id and key_id reach the browser.
  3. When Razorpay captures the payment, the wallet is credited automatically, even if the payer closes the window. Calling POST/billing/verify-payment with razorpay_order_id, razorpay_payment_id and razorpay_signature from the success handler is optional and only makes the credit instant. Calling it twice is safe.

Create an order when the payer clicks to pay, not ahead of time: orders and links share the 10-a-minute limit.

No Razorpay code on your side. You get a hosted page URL to redirect to, or to send by email or WhatsApp.

curl -X POST https://voice-api.edesy.in/v1/billing/payment-links \
  -H "Authorization: Bearer $EDESY_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "amount": 500, "callback_url": "https://admin.example.com/wallet/paid" }'
Field Required Description
amount yes INR to credit, before GST. Minimum 10
gstin no GSTIN for the tax invoice
callback_url no https:// page the payer returns to after paying
expire_in_minutes no Default 10080 (7 days); 16 minutes to 180 days
description no Shown on the payment page

The response has short_url, payment_link_id, payment_id, the GST breakdown and expires_at. Razorpay does not SMS or email the link: delivering it is up to you.

Know when it landed#

A redirect to callback_url, or Checkout's success handler, only means the payer finished on Razorpay's side. Credit your own records on one of these:

  • Webhook: wallet.recharged, once per credited recharge, carrying the payment_id.
  • Poll: GET/billing/payments/{id} with the payment_id, the order_... id or the plink_... id, until status is completed.
status Meaning
pending Not paid yet
completed Credited; invoice_number is set
failed For example, an expired link
refunded Refunded

Wallet webhooks#

Edesy already emails the account owner when the balance runs low. Subscribe a webhook to get the same signal on your server:

curl -X POST https://voice-api.edesy.in/v1/webhooks/subscriptions \
  -H "Authorization: Bearer $EDESY_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://admin.example.com/edesy/webhooks",
        "event_types": ["wallet.low_balance", "wallet.recharged"],
        "secret": "a-long-random-string" }'
Event When
wallet.low_balance A charge takes the balance below the threshold, and again once a day while it stays below and you hold an active number
wallet.recharged A recharge is credited
{ "event": "wallet.recharged", "timestamp": "...",
  "data": { "account_sid": "AC_...", "balance": 594.5, "currency": "INR", "amount": 500, "total": 590,
            "payment_id": "...", "invoice_number": "...", "occurred_at": "..." } }
  • List the wallet events by name in event_types. A subscription with an empty list ("all events") receives call events only, never wallet events. Leave format out (or legacy).
  • With a secret, each delivery carries X-Edesy-Signature: sha256=<hex HMAC-SHA256 of the raw body>; X-Edesy-Event carries the event name. See Verify Signatures.
  • Answer 2xx within 5 seconds. Failed deliveries are retried with backoff, up to 6 attempts, and can be replayed. See Retries and Replay.
  • Use payment_id to ignore a repeat delivery.

History and invoices#

GET/billing/transactions is the ledger, newest first: recharges, call charges, number rentals and refunds, with the balance after each. Filter with type (credit or debit), date_from, date_to (IST days) and ref_type; per_page up to 200. Call rows carry call_sid and, where possible, an itemised call_breakdown. GET/billing/transactions.csv returns the same as CSV.

GET/billing/invoices lists completed recharges with their invoice numbers. Download one with GET/billing/payments/{id}/invoice?format=pdf (HTML without format).

See also Wallet and GST Invoices for how charges are deducted.

FAQ#

Can my customers recharge without seeing my API key?#

Yes. Your server calls Edesy. The browser only ever sees a recharge's order_id and key_id, or a payment link's short_url.

Whose name appears on the Razorpay window?#

Edesy's, because Edesy issues the GST invoice for the recharge.

Do I have to call Verify Payment?#

No. Razorpay notifies Edesy directly and the wallet is credited without it, a few seconds later.

Why am I getting 429?#

More than 10 orders or links in a minute on one account. Wait for the Retry-After seconds, and create orders only when someone clicks to pay.

Can I put my GSTIN on the invoice?#

Yes. Pass gstin when you create the order or link, or set it in your billing profile.

Was this page helpful?