Errors & Limits
Available for accounts in India.
Every error from the Reseller API has the same shape and a message you can show to a person. This page explains each status code and how to handle rate limits.
Shape
Every failure looks the same:
{
"success": false,
"message": "You don't have permission to perform this action. Contact your reseller admin.",
"missing_permission": "clients:billing"
}Check success rather than guessing from the status code. Some endpoints return 200 with fewer fields on purpose (see Omitted fields below).
Status codes
401 is never worth retrying
A 401 means the key itself is bad. A missing key gets a message telling you how to send one. A wrong, revoked or expired key all get the same message, Invalid, revoked, or expired API key., on purpose: telling them apart only helps someone guessing keys.
Retrying a 401 fails the same way forever. Alert a person.
403 tells you what is missing
{ "success": false, "message": "…", "missing_permission": "wallet:view" }{ "success": false, "message": "Your account does not include this product.", "missing_product": "rcs" }The first is fixed by creating a key with that scope. The second means your account does not carry that product at all, and no key can grant it.
Rate limits
120 requests per minute per key by default. You do not choose it: we set it, and support can raise it for your whole account if an integration really needs more. Your API Keys page shows the limit that applies now.
Every response carries the current state:
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 118On 429:
Retry-After: 60Handling it
Read X-RateLimit-Remaining and slow down before you reach zero. If you only react to 429, some requests have already been refused.
On a 429, wait the full Retry-After. The window is a fixed minute, so retrying sooner only wastes another request.
async function call(path, key) {
const res = await fetch(`https://apis.splashifypro.com/api/v1/reseller-api${path}`, {
headers: { Authorization: `Bearer ${key}` },
});
if (res.status === 429) {
const wait = Number(res.headers.get("Retry-After") || 60);
await new Promise(r => setTimeout(r, wait * 1000));
return call(path, key);
}
// A bad key never becomes good. Fail loudly instead of looping.
if (res.status === 401) throw new Error("API key rejected. Check it has not been revoked.");
return res.json();
}Limits are per key
One runaway integration cannot starve your others. Your reseller panel signs in with your login, not a key, so it is never slowed down by your API use.
If you hit the limit for a good reason, ask support to raise it rather than making a second key to get around it. Two keys doing one job make Last used useless for spotting what is still in use, and the limit applies to each key anyway.
Omitted fields
Some endpoints return 200 with fewer fields than you might expect. That is the scope system, not an error.
/dashboard/stats without markup:view returns every count but no subscription_profit or message_profit. The fields are absent, not zero. A zero would say "you earned nothing", which is worse than saying nothing.
Write your integration to treat a missing field as "not allowed", not as 0.
Retrying safely
GET requests are safe to retry.
Writes are not safe to repeat. Retrying POST /clients/{id}/wallet after a timeout may credit twice. If a write times out, read the current state back before you retry.
When your account is not active
A suspended or locked account gets 403 on every endpoint:
{ "success": false, "message": "This reseller account is locked. Contact support." }{ "success": false, "message": "This reseller account is not active." }Your keys start working again once the account is active. There is nothing to reissue.