API Documentation

Perfectpanel-compatible REST API. Share this page with your developer for full integration instructions.

HTTP Method
POST
API URL
https://your-panel.com/api/v2
Response format
JSON

Authentication

Every request must include your API key parameter. Generate or rotate your key from your dashboard under API. Only one active key per account — generating a new key revokes the previous one.

POST https://your-panel.com/api/v2
Content-Type: application/x-www-form-urlencoded

key=YOUR_API_KEY&action=balance

Order status lifecycle

StatusMeaning
pendingReceived, queued for the provider.
processingSubmitted to provider, awaiting confirmation.
in_progressProvider is delivering the order.
completedDelivery finished successfully.
partialPartial delivery; remainder refunded.
canceledCanceled; full refund issued.
refundedOrder failed and refunded to balance.

Endpoints

All requests use HTTP POST with form-encoded or JSON body.

Service list

Returns all active services with current rates and limits.

Parameters
keyYour API key
action"services"
Example request
curl -X POST https://your-panel.com/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=services"
Example response
[
  {
    "service": "1234",
    "name": "Instagram Followers — Real",
    "type": "Default",
    "category": "Instagram",
    "rate": "0.90",
    "min": "100",
    "max": "10000",
    "refill": true,
    "cancel": true
  }
]

Add order

Place a new order. The returned order ID is what you'll use for status and refill calls.

Parameters
keyYour API key
action"add"
serviceService ID from /services
linkTarget URL (profile, post, etc.)
quantityNumber of units to deliver
Example request
curl -X POST https://your-panel.com/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=add" \
  -d "service=1234" \
  -d "link=https://instagram.com/yourpage" \
  -d "quantity=1000"
Example response
{ "order": 87654 }

Order status

Get the current status of a single order.

Parameters
keyYour API key
action"status"
orderOrder ID
Example request
curl -X POST https://your-panel.com/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=status" \
  -d "order=87654"
Example response
{
  "charge": "1.0800",
  "start_count": "1200",
  "status": "In progress",
  "remains": "157",
  "currency": "USD"
}

Multiple orders status

Check up to 100 orders in one request. Comma-separated IDs.

Parameters
keyYour API key
action"status"
ordersid1,id2,id3
Example request
curl -X POST https://your-panel.com/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=status" \
  -d "orders=87654,87655,87656"
Example response
{
  "87654": { "charge": "0.90", "status": "Completed", "remains": "0", "start_count": "1000", "currency": "USD" },
  "87655": { "charge": "1.40", "status": "In progress", "remains": "230", "start_count": "1200", "currency": "USD" }
}

Create refill

Request a refill for a single order (where supported).

Parameters
keyYour API key
action"refill"
orderOrder ID
Example request
curl -X POST https://your-panel.com/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=refill" \
  -d "order=87654"
Example response
{ "refill": "1234" }

Multiple refills

Request refills for multiple orders at once.

Parameters
keyYour API key
action"refill"
ordersid1,id2,id3
Example request
curl -X POST https://your-panel.com/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=refill" \
  -d "orders=87654,87655"
Example response
[
  { "order": 87654, "refill": "1234" },
  { "order": 87655, "refill": { "error": "Incorrect order ID" } }
]

Refill status

Check the status of a single refill request.

Parameters
keyYour API key
action"refill_status"
refillRefill ID
Example request
curl -X POST https://your-panel.com/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=refill_status" \
  -d "refill=1234"
Example response
{ "status": "Completed" }

Multiple refill status

Check status for up to 100 refills.

Parameters
keyYour API key
action"refill_status"
refillsid1,id2,id3
Example request
curl -X POST https://your-panel.com/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=refill_status" \
  -d "refills=1234,1235"
Example response
[
  { "refill": 1234, "status": "Completed" },
  { "refill": 1235, "status": "Pending" }
]

Cancel orders

Request cancellation for one or more orders (where supported).

Parameters
keyYour API key
action"cancel"
ordersid1,id2,id3
Example request
curl -X POST https://your-panel.com/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=cancel" \
  -d "orders=87654,87655"
Example response
[
  { "order": 87654, "cancel": { "status": "Pending" } },
  { "order": 87655, "cancel": { "error": "Incorrect order ID" } }
]

User balance

Get your current account balance.

Parameters
keyYour API key
action"balance"
Example request
curl -X POST https://your-panel.com/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=balance"
Example response
{ "balance": "120.45", "currency": "USD" }

Errors

Errors are returned as JSON with an error field. Common errors:

Incorrect API keyKey missing, revoked, or invalid.
Not enough fundsAdd funds to your account before placing the order.
Incorrect service IDService no longer active. Refetch /services.
Quantity out of rangeAdjust quantity to fit the service's min/max.
Incorrect order IDOrder doesn't exist or doesn't belong to your account.

Rate limits & idempotency

  • Reasonable use is allowed; sustained bursts above ~10 req/s per key may be throttled.
  • Duplicate add requests with the same service + link + quantity received within seconds are de-duplicated server-side to prevent double-charging — the same order ID is returned.
  • Always store the returned order ID and use it for subsequent status/refill/cancel calls.

Code samples

PHP

<?php
$api = new Api();
$api->set_url('https://your-panel.com/api/v2');
$api->set_key('YOUR_API_KEY');

print_r($api->order(['service' => 1234, 'link' => 'https://...', 'quantity' => 1000]));
print_r($api->status(87654));
print_r($api->balance());

class Api {
  private $api_url, $api_key;
  public function set_url($u){ $this->api_url = $u; }
  public function set_key($k){ $this->api_key = $k; }
  public function order($d){ return $this->connect(array_merge(['action'=>'add'], $d)); }
  public function status($id){ return $this->connect(['action'=>'status','order'=>$id]); }
  public function balance(){ return $this->connect(['action'=>'balance']); }
  private function connect($post){
    $_post = ['key'=>$this->api_key];
    foreach($post as $n=>$v) $_post[$n]=$v;
    $ch = curl_init($this->api_url);
    curl_setopt_array($ch, [
      CURLOPT_POST=>true, CURLOPT_RETURNTRANSFER=>true,
      CURLOPT_POSTFIELDS=>http_build_query($_post),
    ]);
    $r = curl_exec($ch); curl_close($ch);
    return json_decode($r, true);
  }
}

Python

import requests

API_URL = "https://your-panel.com/api/v2"
API_KEY = "YOUR_API_KEY"

def call(action, **kwargs):
    return requests.post(API_URL, data={"key": API_KEY, "action": action, **kwargs}).json()

print(call("balance"))
print(call("add", service=1234, link="https://instagram.com/yourpage", quantity=1000))
print(call("status", order=87654))

Node.js

const API_URL = "https://your-panel.com/api/v2";
const API_KEY = "YOUR_API_KEY";

async function call(action, params = {}) {
  const body = new URLSearchParams({ key: API_KEY, action, ...params });
  const res = await fetch(API_URL, { method: "POST", body });
  return res.json();
}

console.log(await call("balance"));
console.log(await call("add", { service: 1234, link: "https://instagram.com/yourpage", quantity: 1000 }));
console.log(await call("status", { order: 87654 }));

Who can use this API

The API is language-agnostic. Any client that can make an HTTPS POST with application/x-www-form-urlencoded or application/json body works — no SDK required.

  • Server languages: PHP (cURL / Guzzle), Python (requests / httpx), Node.js (fetch / axios), Go, Ruby, Java, .NET, Rust, Deno, Bun.
  • No-code / low-code: Make, Zapier, n8n, Pipedream — use their generic HTTP module.
  • SMM panel scripts: Perfectpanel, SmartPanel, YoyoMedia, MedanPanel and any Perfectpanel-compatible fork can add us as an upstream provider.
  • Mobile apps: Android (OkHttp / Retrofit), iOS (URLSession), Flutter (http), React Native (fetch).

No IP whitelisting is required — the API key is the only credential. Rotate it from your dashboard the moment you suspect a leak.

Connect from another SMM panel (as a provider)

Almost every SMM panel script supports adding an external "API provider". Paste these fields exactly — the same values work on Perfectpanel, SmartPanel, YoyoMedia, MedanPanel, Rocket-Panel, and any Perfectpanel fork.

NameAny label you like (e.g. our brand)
API URLhttps://your-panel.com/api/v2
API KeyYour key from Dashboard → API
HTTP MethodPOST
Response formatJSON
Service ID fieldservice — use our numeric public ID, NOT your local service ID

Importing services into your panel

  1. Save the provider, then click Sync or Import services. Your panel calls action=services and stores every service with its ID, rate, min, max, refill/cancel flags, and description.
  2. Set your markup before publishing. Common resellers use rate × 1.2 to rate × 2 (20–100% margin). If you sell in a different currency, apply your FX rate first, then the markup.
  3. Enable auto-sync every 1–6 hours. Rates, min/max, and default descriptions can change on our side — a stale local copy causes failed orders or thin margins.
  4. Map order status labels 1:1 — we already return Pending / Processing / In progress / Completed / Partial / Canceled / Refunded, matching the Perfectpanel spec.

Recommended sync cadence

  • Service list: every 3–6 hours (or on-demand via a Sync button).
  • Order status: every 2–5 minutes for non-terminal orders; stop polling once status is Completed / Canceled / Refunded / Partial.
  • Balance: check before every batch — abort the batch if balance is insufficient instead of firing failing orders one by one.

Mandatory integration checklist

Anyone building a new app, panel, or bot against this API must follow every point below. Skipping any of these is how duplicate orders, double refunds, and support tickets happen.

  1. Store our returned order ID immediately, in the same transaction that debits your user. Never re-issue an add call for the same user action, even if your HTTP client times out. If you don't have the order ID back, use the idempotency flow (next point) — never blindly retry.
  2. Send an idempotency key on every add request.Include idempotency_key (any unique string ≤ 64 chars, e.g. a UUID v4 you generate per order). If the same key is retried within 24 hours, we return the original order ID and do not charge again — safe to retry on network errors, 5xx, or client crashes.
    curl -X POST https://your-panel.com/api/v2 \
      -d "key=YOUR_API_KEY" \
      -d "action=add" \
      -d "service=1234" \
      -d "link=https://instagram.com/yourpage" \
      -d "quantity=1000" \
      -d "idempotency_key=your-uuid-v4-here"
  3. Validate service, link, and quantity client-side first.Check quantity against the service's min/max and confirm the link matches the platform (Instagram URL for Instagram services, etc.). A rejected order is instant on our side but local validation saves a round trip.
  4. Never poll status more than once every 60 seconds for a single order.Prefer the batch status endpoint (up to 100 IDs per call). Stop polling as soon as the order reaches a terminal state.
  5. Handle refunds exactly once.A canceled / refunded / partial order returns the money to your balance on our side. It is your job to credit your end-user only if you haven't already. Track a refund_processed flag per order in your DB and check it before crediting. This is the #1 cause of double refunds.
  6. Show real error messages.Business errors come back as HTTP 200 with an error field (Perfectpanel spec). Read the JSON body, not just the status code. HTTP 401 means the key is invalid — surface it as "API disconnected" in your admin panel.
  7. Use HTTPS. Never log the key parameter to files, analytics, or third-party error trackers.
  8. Respect rate limits. Sustained bursts above ~10 req/s per key may be throttled. Batch where possible — status, refill, and cancel all support multi-ID variants.

How we prevent duplicate orders & double refunds

The API is designed so a badly-written client cannot easily double-charge or double-refund an end user. Guarantees on our side:

  • Idempotency by key: passing idempotency_key returns the same order ID for 24h. Balance is debited exactly once.
  • Fingerprint dedup: even without a key, two identical add calls (same service + link + quantity) from the same account within a short window are collapsed into one order.
  • Atomic charge: balance debit and order row are written in a single DB transaction — a network failure at our end never leaves you charged with no order.
  • One-shot refunds: a canceled / refunded / partial order can only credit balance once. Re-checking status after refund never re-issues funds.
  • Terminal status is final: once Completed / Canceled / Refunded / Partial, the status does not change — safe to archive on your side.

Your side: mirror this. Wrap the add call + user debit + local order insert in one transaction, and never credit a user for a refund without checking an "already refunded" flag.

SMM panel manager basics

If you run an SMM panel and this is your first upstream integration, this checklist covers the operational side the API alone can't do for you.

  • Services are imported, not automatic. After adding us as a provider, click Import services once, then run Sync on a schedule. New services we add later appear only after a sync — automation is your responsibility.
  • Set markup per category, not globally. Instagram followers and YouTube watch-time have very different competitive rates. A flat 2× markup will overprice one and underprice the other.
  • Keep a floor balance with us. If your balance hits zero, every new order fails instantly. Set a low-balance email alert at, say, 10% of your daily volume.
  • Descriptions matter. Import our description field verbatim (start count, refill window, drip rules). Rewriting them causes the most refund disputes.
  • Test with 1 unit first. When you add a new service to your storefront, place a real order at the minimum quantity from a test account before enabling it publicly.
  • Cancel is best-effort. Some services support cancel only before delivery starts. Show your users "Cancel requested", never "Canceled", until we return the terminal status.
  • Refill ≠ refund. Refill re-tops up dropped counts on the same order; refund returns money. Don't wire them to the same button.
  • Log every API response. When a customer disputes an order, the raw JSON we returned at add and status time is the fastest way to resolve it.

Need help? Contact support from your dashboard.