Overview
Base URL: https://nexcoddigital.in/api/v1/
Every service — SMS, OTP, WhatsApp, email, voice, KYC, payments, recharge, utility — is called the same way: POST /services/{CODE} with its parameters as JSON. The price comes from your wallet; if the request fails you are refunded at once.
Authentication
Create keys in your account under API keys. Send the key in the Authorization header (or X-API-Key). Keys are shown once; keep them on your server, never in an app or web page.
Authorization: Bearer nxd_live_9f2c…
Keys can be locked to your server IPs. Calls from any other IP get ip_not_allowed.
Sandbox
Keys that start with nxd_test_ run in the sandbox: parameters are checked exactly as in live, a success response is returned, no provider is called and nothing is charged. KYC is not needed for test keys. You can also try every service from the API console.
POST/services/{CODE}
Runs a service. Put its parameters at the top level of the JSON body (or inside "params"). Add an optional client_ref — your own id for the request, up to 64 characters.
curl -X POST https://nexcoddigital.in/api/v1//services/SMS_TXN \
-H "Authorization: Bearer nxd_live_…" \
-H "Content-Type: application/json" \
-d '{
"mobile": "9876543210",
"message": "Your order 1024 is confirmed.",
"template_id": "1707160000000000000",
"client_ref": "order-1024"
}'
Services with amount + fee charging (recharge, bill payment, payout) take an amount in rupees; your wallet is debited the amount plus the service fee.
GET/transactions/{REF}
Returns one request by our reference — use it to check a pending request. GET/transactions?client_ref=order-1024 finds it by your id; without a filter it lists your latest requests (limit up to 100).
GET/balance
{ "ok": true, "balance": 4821.64, "currency": "INR", "account": "NXD10024", "mode": "live" }
GET/services
Every service available to you with your price, its unit, charging type, status and parameter list.
Response
Every request answers HTTP 200 with this shape when it was processed, whether the provider succeeded or not. Check ok and status.
{
"ok": true,
"ref": "NXD7K2M9QH4TPX", // our reference
"client_ref": "order-1024",
"service": "SMS_TXN",
"status": "success", // success | pending | refunded
"mode": "live",
"charged": 0.18,
"balance": 4821.64,
"provider_ref": "a1b2c3",
"data": { }, // service-specific fields
"created_at": "2026-10-21T10:15:00+05:30"
}
| status | Meaning |
success | Done. Charged. |
pending | Accepted by the provider, final result not yet known (common for recharge and payouts). Charged now; if it finally fails it is refunded to your wallet. You get a webhook either way. |
refunded | Failed. ok is false, error says why, nothing was charged. |
Errors
Requests that are refused before processing return {"ok": false, "error": {"code", "message"}} with the HTTP status below.
| code | HTTP | Meaning |
unauthorized | 401 | Missing, malformed or revoked API key. |
account_inactive | 403 | The account is suspended or waiting for approval. |
ip_not_allowed | 403 | The calling IP is not on the key's whitelist. |
kyc_required | 403 | Live keys need verified KYC. Test keys work without it. |
service_not_found | 404 | No service with that code. List them with GET /services. |
missing_params | 422 | A required parameter is missing. |
invalid_param | 422 | A parameter is not in the expected format. |
invalid_json | 400 | The request body is not valid JSON. |
insufficient_balance | 402 | The wallet cannot cover the request. Nothing was charged. |
daily_limit_reached | 429 | The account's daily spend cap is reached. |
rate_limited | 429 | More than the per-minute limit (default 120) for this key. Retry after 60 seconds. |
service_maintenance | 503 | The service is paused for maintenance. |
request_failed | 200 | The provider could not complete it. ok is false, status is refunded, and you were not charged. |
Idempotency
Send the same client_ref again — after a timeout, say — and you get the first request's result back with "duplicate": true. It is never run or charged twice.
Webhooks
Add HTTPS endpoints under Webhooks. We POST JSON for these events:
| Event | When |
|---|
transaction.success | Request succeeded |
transaction.failed | Request failed |
transaction.pending | Request pending |
transaction.refunded | Request refunded |
wallet.credited | Wallet credited |
wallet.low_balance | Wallet balance low |
Headers: X-Nexcod-Event, X-Nexcod-Timestamp and X-Nexcod-Signature: sha256=…, the HMAC-SHA256 of timestamp + "." + raw body with the endpoint's secret. Answer 2xx within 10 seconds; otherwise we retry after 1, 5, 30, 120 and 360 minutes.
// Node.js (Express, raw body)
const crypto = require('crypto');
const sig = crypto.createHmac('sha256', process.env.NEXCOD_WEBHOOK_SECRET)
.update(req.get('X-Nexcod-Timestamp') + '.' + req.rawBody).digest('hex');
if ('sha256=' + sig !== req.get('X-Nexcod-Signature')) return res.sendStatus(401);
Limits
120 requests a minute per key by default (ask support to raise it). Accounts can also carry a daily spend cap. Over the limit you get HTTP 429 with Retry-After: 60.
Code samples
Python
import os, requests
r = requests.post("https://nexcoddigital.in/api/v1//services/KYC_PAN",
headers={"Authorization": "Bearer " + os.environ["NEXCOD_KEY"]},
json={"pan": "ABCDE1234F", "client_ref": "kyc-77"}, timeout=40)
res = r.json()
if res["ok"]: print(res["data"])
Node.js
const res = await fetch('https://nexcoddigital.in/api/v1//services/RC_MOBILE', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.NEXCOD_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ mobile: '9876543210', operator: 'JIO', amount: '299', client_ref: 'rc-501' }),
}).then(r => r.json());
Service catalogue
Codes and parameters. * = required. Your prices are in your account and in GET /services.
Email
EMAIL_SEND · Transactional email (coming soon) | fixed price, per email |
to * | To email — e.g. customer@example.com |
subject * | Subject — e.g. Your invoice |
html * | HTML body — e.g. <p>Hello</p> |
from_name | From name — e.g. Your Brand |
KYC & Verification
KYC_PAN · PAN verification (coming soon) | fixed price, per check |
pan * | PAN — e.g. ABCDE1234F |
name | Name to match — e.g. Ravi Kumar |
KYC_GSTIN · GSTIN verification (coming soon) | fixed price, per check |
gstin * | GSTIN — e.g. 27ABCDE1234F1Z5 |
KYC_BANK · Bank account verification (coming soon) | fixed price, per check |
account * | Account number — e.g. 50100012345678 |
ifsc * | IFSC — e.g. HDFC0001234 |
KYC_UPI · UPI ID verification (coming soon) | fixed price, per check |
vpa * | UPI ID — e.g. name@bank |
Other APIs
LOOKUP_IFSC · IFSC lookup (coming soon) | fixed price, per lookup |
ifsc * | IFSC — e.g. HDFC0001234 |
LOOKUP_PINCODE · Pincode lookup (coming soon) | fixed price, per lookup |
pincode * | Pincode — e.g. 110001 |
OTP
OTP_SMS · OTP over SMS (coming soon) | fixed price, per OTP |
mobile * | Mobile number — e.g. 9876543210 |
otp | OTP (leave empty to let us generate it) — e.g. 482913 |
template_id | DLT template ID — e.g. 1707160000000000000 |
OTP_VOICE · OTP over voice call (coming soon) | fixed price, per call |
mobile * | Mobile number — e.g. 9876543210 |
otp * | OTP — e.g. 482913 |
Payments
PAY_LINK · Payment link (coming soon) | fixed price, per link |
amount * | Amount (₹) — e.g. 499.00 |
purpose * | Purpose — e.g. Invoice 1024 |
mobile | Customer mobile — e.g. 9876543210 |
email | Customer email — e.g. customer@example.com |
PAYOUT_IMPS · Payout (IMPS) (coming soon) | amount + fee, per payout |
amount * | Amount (₹) — e.g. 1000.00 |
account * | Account number — e.g. 50100012345678 |
ifsc * | IFSC — e.g. HDFC0001234 |
name * | Beneficiary name — e.g. Ravi Kumar |
Recharge
RC_MOBILE · Mobile recharge (coming soon) | amount + fee, per recharge |
mobile * | Mobile number — e.g. 9876543210 |
operator * | Operator — e.g. JIO |
amount * | Amount (₹) — e.g. 299 |
circle | Circle — e.g. DL |
RC_DTH · DTH recharge (coming soon) | amount + fee, per recharge |
subscriber_id * | Subscriber ID — e.g. 1234567890 |
operator * | Operator — e.g. TATAPLAY |
amount * | Amount (₹) — e.g. 350 |
SMS
SMS_TXN · Transactional SMS (coming soon) | fixed price, per SMS |
mobile * | Mobile number — e.g. 9876543210 |
message * | Message text — e.g. Your order 1024 is confirmed. |
template_id | DLT template ID — e.g. 1707160000000000000 |
sender | Sender ID — e.g. NEXCOD |
SMS_PROMO · Promotional SMS (coming soon) | fixed price, per SMS |
mobile * | Mobile number — e.g. 9876543210 |
message * | Message text — e.g. Flat 20% off this weekend. |
template_id | DLT template ID — e.g. 1707160000000000000 |
Utility & BBPS
BILL_FETCH · Bill fetch (BBPS) (coming soon) | fixed price, per fetch |
biller_id * | Biller ID — e.g. MSEDCL000MAH01 |
consumer_no * | Consumer number — e.g. 170012345678 |
BILL_PAY · Bill payment (BBPS) (coming soon) | amount + fee, per payment |
biller_id * | Biller ID — e.g. MSEDCL000MAH01 |
consumer_no * | Consumer number — e.g. 170012345678 |
amount * | Amount (₹) — e.g. 1240.00 |
FASTAG · FASTag recharge (coming soon) | amount + fee, per recharge |
vehicle_no * | Vehicle number — e.g. MH12AB1234 |
operator * | FASTag bank — e.g. ICICI |
amount * | Amount (₹) — e.g. 500 |
Voice
VOICE_CALL · Voice broadcast call (coming soon) | fixed price, per call |
mobile * | Mobile number — e.g. 9876543210 |
audio_url | Audio URL — e.g. https://example.com/msg.mp3 |
text | Text to speak — e.g. Your appointment is tomorrow at 10 AM. |
WhatsApp
WA_TEMPLATE · WhatsApp template message (coming soon) | fixed price, per message |
mobile * | Mobile number — e.g. 9876543210 |
template * | Template name — e.g. order_update |
variables | Variables (comma separated) — e.g. Ravi,1024 |
media_url | Media URL — e.g. https://example.com/invoice.pdf |
WA_TEXT · WhatsApp session message (coming soon) | fixed price, per message |
mobile * | Mobile number — e.g. 9876543210 |
message * | Message text — e.g. Thanks, your ticket is resolved. |