Reseller API
Connect your own panel or app to SMM Panel. The API follows the standard SMM panel API v2, so most panel scripts can add us as a provider with the endpoint below and your key.
https://abisektamang.com/api/v2
Quick start
- Create an API key on the API access page. Choose what the key may do and, if you like, which IP addresses may use it. The key is shown only once, so store it somewhere safe.
- Send a POST request to the endpoint with your
keyand anaction. - Read the JSON response. Problems come back as
{"error": "…"}, so check for anerrorfield in every response.
curl -X POST https://abisektamang.com/api/v2 \
-d key=YOUR_API_KEY \
-d action=balance
Requests and responses
| Item | Details |
|---|---|
| Endpoint | https://abisektamang.com/api/v2 |
| Method | POST. GET with a query string also works, but it can leave your key in server logs, so prefer POST. |
| Body | Form fields (application/x-www-form-urlencoded or multipart/form-data), or a JSON object sent with Content-Type: application/json. |
| Response | JSON in UTF-8. |
| Amounts | Strings in NPR with 2 to 5 decimals, for example "163.03" or "0.8631". |
| Several IDs | Put them in one parameter, separated by commas or spaces, up to 100 per request. |
Keys and permissions
Every request needs your key. Each key has its own permissions. Using an action the key is not allowed to use returns an error.
| Permission | Actions |
|---|---|
| List services | services |
| Place orders | add |
| Check order status | status |
| Check balance | balance |
| Request refills | refill, refill_status |
| Request cancellations | cancel |
If you limit a key to certain IP addresses, requests from any other address get an error. Call the API from your own server and never put your key in a web page or app that other people can inspect. Lost a key? Rotate or revoke it on the API access page.
Service list
Returns every service you can order, with your prices after any account discount.
| Parameter | Required | Description |
|---|---|---|
key | Yes | Your API key. |
action | Yes | services |
curl -X POST https://abisektamang.com/api/v2 \
-d key=YOUR_API_KEY \
-d action=services [
{
"service": 1,
"name": "Instagram Followers",
"type": "Default",
"category": "Instagram",
"rate": "163.03",
"min": "50",
"max": "50000",
"refill": true,
"cancel": true,
"dripfeed": false
},
{
"service": 4,
"name": "Instagram Custom Comments",
"type": "Custom Comments",
"category": "Instagram",
"rate": "863.10",
"min": "5",
"max": "1000",
"refill": false,
"cancel": false,
"dripfeed": false
}
] | Field | Meaning |
|---|---|
service | Service ID to use with add. |
type | Which parameters add needs. See the table of service types below. |
rate | Price per 1,000 in NPR, or per order for the Package type. |
min, max | Smallest and largest quantity per order. |
refill, cancel, dripfeed | Whether refills, cancellations and drip-feed are available. |
Add an order
Places an order and pays for it from your balance right away. The response is the new order ID.
| Parameter | Required | Description |
|---|---|---|
key | Yes | Your API key. |
action | Yes | add |
service | Yes | Service ID from the service list. |
link | Most types | Public link to the profile, post or video. Never send a password. |
quantity | Most types | How many to deliver, between the service min and max. |
runs | No | Drip-feed: number of deliveries, 2 to 1,000. |
interval | No | Drip-feed: minutes between deliveries, 1 to 10,080. |
idempotency_key | No | Your own unique reference for this order. See avoiding duplicate orders below. client_key and external_id work too. |
curl -X POST https://abisektamang.com/api/v2 \
-d key=YOUR_API_KEY \
-d action=add \
-d service=1 \
--data-urlencode "link=https://www.instagram.com/yourprofile/" \
-d quantity=1000 {
"order": 23501
}
Parameters by service type
The type in the service list tells you what to send besides service.
| Type | Parameters |
|---|---|
Default | link, quantity |
Package | link. The price is per order, so no quantity. |
Custom Comments | link, comments: one comment per line. The number of lines is the quantity. |
Mentions Custom List | link, usernames: one username per line. The number of lines is the quantity. |
Mentions Hashtag | link, quantity, hashtag |
Mentions User Followers | link, quantity, username |
Comment Likes | link, quantity, username of the comment author |
Poll | link, quantity, answer_number from 1 to 20 |
Subscriptions | username, min and max per post, posts (1 to 1,000 new posts), delay in minutes (0, 5, 10, 15, 30, 60 or 90) and optionally expiry, a future date as YYYY-MM-DD or DD/MM/YYYY. The charge covers max × posts. |
In one-per-line fields, separate lines with a newline or with the two characters \n.
Drip-feed
For services with "dripfeed": true, send runs and interval to split delivery over time. The quantity is delivered in every run, so the charge is the price of quantity × runs.
Avoiding duplicate orders
Network errors happen. Send idempotency_key with a value that is unique for each of your orders. If you retry with a key you already used, for the same service, link and quantity, you get the original order ID back and are not charged again. The same key with other order details is refused with an error. Keys are compared without regard to letter case or accents, and webhooks repeat a key of up to 60 characters exactly as you sent it.
Some services refuse a second active order for the same link. In that case the response is an error naming the active order.
Order status
| Parameter | Required | Description |
|---|---|---|
key | Yes | Your API key. |
action | Yes | status |
order | One of these | A single order ID. |
orders | One of these | Up to 100 order IDs, separated by commas. |
curl -X POST https://abisektamang.com/api/v2 \
-d key=YOUR_API_KEY \
-d action=status \
-d order=1001 {
"charge": "16.30",
"start_count": "1250",
"status": "In progress",
"remains": "430",
"currency": "NPR"
} {
"1001": {
"charge": "16.30",
"start_count": "1250",
"status": "In progress",
"remains": "430",
"currency": "NPR"
},
"1002": {
"error": "Incorrect order ID"
}
} | Field | Meaning |
|---|---|
charge | What the order cost, minus anything refunded. |
start_count | The count when delivery started, or "0" when unknown. |
remains | How many are still to be delivered. |
status | Pending (received, not started yet), Processing, In progress, Completed, Partial (part delivered, the rest refunded) or Canceled (refunded). |
currency | Currency of charge. |
Refills
For services with "refill": true. An order can be refilled once it is completed or partial, within the refill period of its service, at most once every 24 hours and one refill at a time.
| Parameter | Required | Description |
|---|---|---|
action | Yes | refill to request a refill, refill_status to check one. |
order / orders | For refill | One order ID, or up to 100 separated by commas. |
refill / refills | For refill_status | One refill ID, or up to 100 separated by commas. |
curl -X POST https://abisektamang.com/api/v2 \
-d key=YOUR_API_KEY \
-d action=refill \
-d order=1001 {
"refill": 412
} [
{
"order": 1001,
"refill": 412
},
{
"order": 1002,
"refill": {
"error": "The refill period for this order has ended."
}
}
] {
"status": "Completed"
} [
{
"refill": 412,
"status": "Completed"
},
{
"refill": 413,
"status": {
"error": "Refill not found"
}
}
] Refill status is Pending, In progress, Completed or Rejected.
Cancel orders
For services with "cancel": true. Orders that have not started are canceled and refunded right away. Orders already being delivered get a cancellation request, and their status shows the result.
| Parameter | Required | Description |
|---|---|---|
action | Yes | cancel |
orders | Yes | Up to 100 order IDs, separated by commas. A single order also works. |
curl -X POST https://abisektamang.com/api/v2 \
-d key=YOUR_API_KEY \
-d action=cancel \
-d orders=1001,1002 [
{
"order": 1001,
"cancel": 1
},
{
"order": 1002,
"cancel": {
"error": "This order can no longer be canceled."
}
}
]
Balance
Your current balance, including any promotional balance.
curl -X POST https://abisektamang.com/api/v2 \
-d key=YOUR_API_KEY \
-d action=balance {
"balance": "1520.75",
"currency": "NPR"
}
Errors
Every error is a JSON object with an error message, like {"error": "Incorrect service ID"}. As in other SMM panels, every answer comes with HTTP status 200, errors included, so always check for error.
| Error | When |
|---|---|
API key is required | The request has no key. |
Invalid API key | The key is wrong or was revoked, or API access is turned off for the account. |
This API key is not allowed to use this action | The key does not have permission for this action. |
The API is disabled. | The API is turned off for this panel. |
Too many requests | Too many requests from your IP address, or too many invalid keys. Wait for the number of seconds in the Retry-After header. |
Rate limit exceeded for this key | This key sent more requests in a minute than it may. Wait for the number of seconds in the Retry-After header. |
Maintenance in progress, please retry later | Maintenance in progress. Try again later. |
Messages you may see:
API key is requiredInvalid API keyIncorrect actionIncorrect service IDIncorrect order IDRefill not foundNot enough funds in your balance.Quantity must be between 50 and 50,000.This API key is not allowed to use this actionRate limit exceeded for this key
Rate limits
- Each key can make up to 120 requests per minute.
- Each IP address can make up to 600 requests per minute across all keys.
- After more than 30 requests with an invalid key from one IP address within 10 minutes, further invalid attempts get
Too many requests.
Over a limit, you get the error Too many requests or Rate limit exceeded for this key with the header Retry-After: 60. To stay well within limits, check up to 100 orders per request with orders instead of one request per order.
Webhooks
Instead of polling status, let us call you. On the API access page, enter one https:// address and you get a signing secret. From then on every status change of your orders and refills is sent to that address as a JSON POST request. Delivery is asynchronous (within about a minute) and retried for up to a day.
Events
| Event | Sent when |
|---|---|
order.processing | The order was accepted by the provider. |
order.in_progress | Delivery has started. |
order.completed | The order is complete. |
order.partial | Part of the order was delivered; the rest was refunded. order.refunded holds the amount. |
order.canceled | The order was canceled and refunded (by you, by staff or by the provider). order.refunded holds the amount. |
refill.in_progress | A refill was accepted by the provider. |
refill.completed | The refill is complete. |
refill.rejected | The refill was refused. refill.reason says why, when known. |
test.ping | Sent by the "Send test event" button. |
Request
| Header | Meaning |
|---|---|
Content-Type | application/json |
X-Panel-Event | The event name, for example order.completed. |
X-Panel-Timestamp | Unix time (seconds) when the delivery was sent. Refuse deliveries older than a few minutes. |
X-Panel-Signature | sha256= followed by the hex HMAC-SHA256 of <timestamp>.<raw body>, keyed with your signing secret. |
X-Panel-Delivery | A number that identifies this delivery. Retries send the same number, so you can ignore duplicates. |
{
"id": 8812,
"event": "order.completed",
"created_at": "2026-10-22T09:14:05+00:00",
"status": "Completed",
"previous_status": "In progress",
"order": {
"id": 23501,
"status": "Completed",
"service": 1,
"service_name": "Instagram Followers",
"link": "https://www.instagram.com/yourprofile/",
"quantity": 1000,
"start_count": 1250,
"remains": 0,
"charge": "163.03",
"refunded": "0.00",
"currency": "NPR",
"idempotency_key": "my-order-1001",
"created_at": "2026-10-22T08:40:11+00:00",
"updated_at": "2026-10-22T09:14:05+00:00"
}
} {
"id": 8813,
"event": "refill.completed",
"created_at": "2026-10-23T11:02:40+00:00",
"status": "Completed",
"refill": {
"id": 412,
"order": 23501,
"status": "Completed",
"reason": null,
"created_at": "2026-10-23T09:00:00+00:00",
"updated_at": "2026-10-23T11:02:40+00:00"
}
} | Field | Meaning |
|---|---|
status, previous_status | The status that triggered the event and the one before it, with the same names as the status action. |
order | The order as it is when the event is sent: charge is what it cost after refunds, refunded what went back to your balance, remains what is still to deliver, idempotency_key your own reference if you sent one. |
refill | The refill with its order ID, status (Pending, In progress, Completed or Rejected) and reason. |
created_at | When the event happened, ISO 8601 in UTC. |
Verifying and answering
- Read the raw request body (not a re-encoded version of it) and compute
sha256=+ HMAC-SHA256(secret, timestamp + "." + body), where timestamp is theX-Panel-Timestampheader. Compare it withX-Panel-Signatureusing a constant-time comparison and refuse deliveries whose timestamp is more than five minutes old. - Answer with any HTTP 2xx status within 10 seconds. Queue slow work instead of doing it before you answer.
- Anything else (timeouts, 3xx, 4xx, 5xx) is retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours. After 20 failures in a row the webhook is turned off and you are notified; turn it on again from the API access page once your endpoint works.
- Events can arrive out of order when retries are involved: use
order.status(the current state) rather than the event name when in doubt, and keep the latestupdated_at.
Only https:// addresses on public hosts are accepted. We do not follow redirects, so point the address straight at your script.
<?php
// webhook.php: verify the signature, then handle the event. Answer 200 quickly; do the slow work later.
$secret = 'YOUR_SIGNING_SECRET';
$body = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_PANEL_SIGNATURE'] ?? '';
$timestamp = (int) ($_SERVER['HTTP_X_PANEL_TIMESTAMP'] ?? 0);
$expected = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . $body, $secret);
if (!hash_equals($expected, $signature) || abs(time() - $timestamp) > 300) {
http_response_code(401);
exit('bad signature or stale delivery');
}
$event = json_decode($body, true);
$deliveryId = (int) ($_SERVER['HTTP_X_PANEL_DELIVERY'] ?? 0); // the same ID is sent again on retries: ignore duplicates
switch ($event['event'] ?? '') {
case 'order.completed':
case 'order.partial':
case 'order.canceled':
// $event['order']['id'], $event['order']['status'], $event['order']['refunded'] ...
break;
case 'refill.completed':
case 'refill.rejected':
// $event['refill']['id'], $event['refill']['order'], $event['refill']['status']
break;
}
http_response_code(200); # Flask example: verify the signature, then handle the event.
import hashlib, hmac, json, time
from flask import Flask, request, abort
app = Flask(__name__)
SECRET = b"YOUR_SIGNING_SECRET"
@app.post("/webhook")
def webhook():
body = request.get_data() # raw bytes, exactly as sent
timestamp = request.headers.get("X-Panel-Timestamp", "0")
expected = "sha256=" + hmac.new(SECRET, timestamp.encode() + b"." + body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, request.headers.get("X-Panel-Signature", "")) or abs(time.time() - int(timestamp)) > 300:
abort(401)
event = json.loads(body)
delivery_id = request.headers.get("X-Panel-Delivery") # same ID on retries: ignore duplicates
if event["event"].startswith("order."):
order = event["order"] # order["id"], order["status"], order["remains"], order["refunded"]
elif event["event"].startswith("refill."):
refill = event["refill"] # refill["id"], refill["order"], refill["status"]
return "", 200
Code examples
curl -X POST https://abisektamang.com/api/v2 \
-d key=YOUR_API_KEY \
-d action=add \
-d service=1 \
--data-urlencode "link=https://www.instagram.com/yourprofile/" \
-d quantity=1000 \
-d idempotency_key=my-order-1001 curl -X POST https://abisektamang.com/api/v2 \
-H "Content-Type: application/json" \
-d '{"key":"YOUR_API_KEY","action":"status","orders":"1001,1002"}' <?php
// Calls the API and returns the decoded JSON, or throws on an error.
function smm_api(array $params): array
{
$ch = curl_init('https://abisektamang.com/api/v2');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query(['key' => 'YOUR_API_KEY'] + $params),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$data = json_decode((string) $body, true);
if (!is_array($data)) {
throw new RuntimeException('Unexpected response (HTTP ' . $status . ')');
}
if (isset($data['error'])) {
throw new RuntimeException($data['error']);
}
return $data;
}
// Place an order. Retrying with the same idempotency_key returns the same order.
$order = smm_api([
'action' => 'add',
'service' => 1,
'link' => 'https://www.instagram.com/yourprofile/',
'quantity' => 1000,
'idempotency_key' => 'my-order-1001',
]);
echo 'Order ID: ' . $order['order'] . PHP_EOL;
// Check its progress later.
$status = smm_api(['action' => 'status', 'order' => $order['order']]);
echo $status['status'] . ', remaining: ' . $status['remains'] . PHP_EOL;