When you wire a panel into a bot, your own site or another panel, an overview of what an API is stops being useful - you need the exact list of calls, their parameters and their response shapes. This reference was built differently from the usual docs: we measured the actual contract across eleven live panels and cross-checked it against our own core. Below are all ten calls, the order fields per service type, and the three places where integrations break most often.
The reference below describes what to call. What the panel itself has to check while you do - quantity limits, duplicates on a link, customer permissions, the request budget - is in a separate article on API abuse: an integration written without those rules in mind runs into them in production.
Why almost every panel speaks the same API
Practically the whole industry speaks one protocol, commonly called API v2. It happened historically: one engine set the format and the rest copied it so that reseller clients written elsewhere would work against them too. For an integrator that is a rare piece of luck - a client written for one panel runs against another with almost no changes.
There are exactly four rules common to all of them:
- A single endpoint. Usually
/api/v2, the method is alwaysPOST, the response is always JSON. - The key is a field, not a header. It travels as an ordinary
keyparameter - noAuthorization, noBearer. - The operation lives in
action. Not the route, not the HTTP method - the value of that field decides what happens. - No versioning outside the path. The "v2" is part of the endpoint, not a header or a parameter.
The practical takeaway for a panel owner: do not invent your own format. A custom protocol cuts you off from resellers who already have an integration written - and they are the ones who bring volume. Why you would hand out keys at all, and to whom, is covered in the panel API and working with resellers.
Seven actions, ten calls
The standard has seven actions, but four of them come in a batch form as well - which makes ten distinct calls to support:
action=services- the service list. Returns an array ofservice(the public number),name,type,category,rate,min,max,refill,cancel.action=add- create an order.serviceis always required; the rest of the fields depend on the service type. The response is{"order": 23501}.action=statuswithorder- one order:charge,start_count,status,remains,currency.action=statuswithorders- up to a hundred comma-separated numbers in one request.action=refillwithorder- create a refill. The response is the refill number, often as a string:{"refill": "1"}.action=refillwithorders- batch refill, up to a hundred orders.action=refill_statuswithrefill- refill state by the refill's own number.action=refill_statuswithrefills- the same in bulk.action=cancelwithorders- cancellation, documented in the batch form only.action=balance-{"balance": "100.84292", "currency": "USD"}.
Anything beyond that list is one panel's extension. Ours, for instance, accepts a single cancel by order and treats action=create as a synonym for add - but a client must never be written against such conveniences, because the next panel will not have them.
Order fields depend on the service type
The biggest misconception on a first integration is that an order is a link and a quantity. That is only the base type. The type field in services arrives as a string name, and it dictates the whole parameter set for add:
- Default -
linkandquantity, with optionalrunsandintervalfor gradual delivery. - Custom Comments -
linkandcomments: no quantity is sent at all, it is derived from the number of lines in the list. - The Mentions family - six separate types that differ only in where the audience comes from: a ready
usernameslist, ahashtag, another account's followers, or the people who liked a specific post. - SEO takes
keywordsalongside the quantity; Poll takesanswer_number, the index of the option to vote for. - Package -
linkonly: no quantity, no extra fields, the volume is baked into the service itself. - Subscriptions - no
linkwhatsoever. Instead there isusername, theminandmaxbounds, adelayfrom a closed list of minute values, and anexpirydate ind/m/Yformat. - Web Traffic - the widest of them:
country,device,type_of_traffic, all three given as numbers from a lookup table rather than words. Keyword traffic additionally requiresgoogle_keyword, a custom referrer requiresreferring_url.
Two technical details trip up nearly everyone. Lists - comments, keywords, usernames, hashtags - are sent as a single string with newlines as separators, not as a JSON array. And the numeric lookups behind device and type_of_traffic never come back in services: you have to know those values from the panel's documentation up front.
One more thing worth admitting plainly: the type numbering has gaps. At least six numbers are known to the engines yet appear in none of the panels we measured. So "we support every type" is a promise nobody can keep - the right strategy for a receiving panel is a clear refusal on an unknown type instead of guessing its fields. What the types actually mean is unpacked in provider service types.
Three places where integrations break
These three are missing from almost every set of docs, and they are exactly what produces the bugs that surface a week after launch.
- The batch response shape depends on the action. For
statusit is an object keyed by order number. Forrefill,refill_statusandcancelit is an array of objects with the number inside each element. One parser for all batch responses will not do. - Per-element errors arrive nested. Not as a request-wide
{"error": ...}, but inside the element itself, under the same key the result would use. Code that only reads the top level will process ninety-nine orders out of a hundred and lose the hundredth in silence. - A refill is addressed by its own number, not the order's.
action=refillreturns a refill number, and that is the only thingrefill_statuswill find it by. There is no order-to-refill link in the API at all: storing that number is the client's job. Some panels also accept an order number there as an extension - ours does, so existing integrations keep working - but the standard has nothing of the kind.
Cancellation belongs on the same list: there is no single-order cancel in the standard, only the batch one. A client cancelling orders one at a time still has to send a list of one and parse an array back.
Statuses and errors are strings, not constants
An order status arrives as human-readable text: Pending, In progress, Processing, Partial, Completed, Canceled, Fail, Error. Refills have their own set - Completed, Rejected and the intermediate In progress - and an unknown refill number comes back as Refill not found.
Which gives a client four rules:
- Compare case-insensitively and do not lean on the spacing: different panels spell the same state in slightly different ways.
- An unknown status is not a failure. It means "nothing changed, ask again later", not "the order died". Otherwise the first time a panel extends its set you get an avalanche of false refunds.
- Parse money as a string.
chargeandbalancecome as strings with four decimal places - going through a float rounds them in somebody else's favour. - Request-level errors are strings too:
Incorrect API key,Incorrect order ID,Incorrect action. The HTTP code may well stay 200, so checking only the code is not enough.
What the statuses mean to the buyer, and what a panel owes them in each state, is covered in SMM panel order statuses; why delivered volume drains away and how refills answer it is in drops and refill.
How to test the integration before production
Six checks that catch almost everything before the first live order:
- Run
servicesand diff the incoming types against what your code handles. An unknown type has to produce a clear refusal, not an order with empty fields. - Place one order of every type you intend to sell. Field-set mistakes only show up this way, because panel-side validation is strict.
- Batch
statuson a hundred numbers, one of which certainly does not exist. That is the nested-error test - the one that otherwise loses orders one at a time. - The full refill cycle:
refill, store the number, askrefill_statusby the refill number. If your code asks by order number and still gets an answer, you are relying on one panel's extension. - A wrong key. The response must still be JSON. If HTML comes back you are looking at a web-server error page rather than the API, and your client has to tell the difference - otherwise an outage on the panel's side looks like a rejection of every order.
- Polling rate. Batches of up to a hundred, no more than once a minute per order, with a growing pause after every failure. Never poll finished orders - that is the most common way to hit a rate limit for nothing.
On the provider side there is extra work: per-key limits, a call log and protection against the same order being submitted twice. What to check before handing a reseller a key is covered in how to sell SMM services as a provider. Whether your own provider is supported on our side can be checked on the provider check page.
Wrap-up
API v2 looks simple - one endpoint, seven actions - and that is precisely why it gets underestimated. The real complexity sits in three spots: the service type dictates the order fields, the batch response shape depends on the action, and a refill lives under a number of its own. A client that respects those three moves between panels with almost no edits; a client that missed them loses orders quietly.
If the API you need is for your own panel rather than someone else's, all of this can be tested with no money down: orders that go through our own catalogue are never billed, however many there are, and on third-party providers the first 100 orders a month are free. The key and full documentation are issued straight away, so you can write a client and exercise all ten calls before the panel has its first customer. How that limit is counted is explained in how the rental plan is calculated.