API
API Documentation
Connect to Panelora from your own panel or app: place orders, check status, request refills and read your balance over a simple HTTP API.
API URL
https://demo.example/api/v2Method
POST
Content type
application/json · form-data
Response format
JSON
error field — always check the body, not just the status code. The key parameter is key.Get balance
action=balanceReturns the current account balance.
| Name | Type | Required | Description |
|---|---|---|---|
| key | string | Yes | Your API key |
| action | string | Yes | balance |
curl -X POST https://demo.example/api/v2 \
-H "Content-Type: application/json" \
-d '{"key":"YOUR_API_KEY","action":"balance"}'
<?php
$ch = curl_init('https://demo.example/api/v2');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'key' => 'YOUR_API_KEY',
'action' => 'balance'
]));
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($response);
import requests
response = requests.post(
"https://demo.example/api/v2",
json={
"key": "YOUR_API_KEY",
"action": "balance"
},
timeout=30,
)
response.raise_for_status()
print(response.json())
const response = await fetch("https://demo.example/api/v2", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
"key": "YOUR_API_KEY",
"action": "balance"
}),
});
console.log(await response.json());
Response
{
"balance": "100.84",
"currency": "INR"
}
Get service list
action=servicesReturns every active service with your personal pricing applied.
| Name | Type | Required | Description |
|---|---|---|---|
| key | string | Yes | Your API key |
| action | string | Yes | services |
curl -X POST https://demo.example/api/v2 \
-H "Content-Type: application/json" \
-d '{"key":"YOUR_API_KEY","action":"services"}'
<?php
$ch = curl_init('https://demo.example/api/v2');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'key' => 'YOUR_API_KEY',
'action' => 'services'
]));
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($response);
import requests
response = requests.post(
"https://demo.example/api/v2",
json={
"key": "YOUR_API_KEY",
"action": "services"
},
timeout=30,
)
response.raise_for_status()
print(response.json())
const response = await fetch("https://demo.example/api/v2", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
"key": "YOUR_API_KEY",
"action": "services"
}),
});
console.log(await response.json());
Response
[
{
"service": 8109,
"name": "Instagram Likes | Real | No Refill | 2K/Day",
"type": "Default",
"category": "Instagram Likes",
"rate": "33.7459",
"min": 100,
"max": 1000,
"refill": true,
"cancel": false,
"dripfeed": true,
"price": 33.7459,
"category_id": 14
}
]
- The response is a plain array, with no wrapper object around it.
rateis the price per 1000 units in your account currency, with your personal pricing and any sale already applied.typeisDefaultorCustom Comments. ACustom Commentsservice needs thecommentsparameter onadd.refill,cancelanddripfeedtell you which of those the service supports.price(numeric) andcategory_idare extras beyond the standard fields — ignore them if your importer does not expect them.
Place an order
action=addCreates a new order and debits the charge from your balance immediately.
| Name | Type | Required | Description |
|---|---|---|---|
| key | string | Yes | Your API key |
| action | string | Yes | add |
| service | int | Yes | Service ID |
| link | string | Yes | Target link / profile URL |
| quantity | int | Yes | Quantity, within the service min/max |
| username | string | No | Username, for services that ask for one instead of a link |
| comments | string | No | Custom comments, one per line (comment services) |
| dripfeed | int | No | Number of runs for drip-feed delivery |
| dripfeed_delivery | string | No | Delivery interval for drip-feed |
| subscriptions_type | int | No | Subscription type (subscription services) |
| subscriptions_expiry | string | No | Subscription expiry date, YYYY-MM-DD |
curl -X POST https://demo.example/api/v2 \
-H "Content-Type: application/json" \
-d '{"key":"YOUR_API_KEY","action":"add","service":8109,"link":"https://instagram.com/p/AbCdEf","quantity":100}'
<?php
$ch = curl_init('https://demo.example/api/v2');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'key' => 'YOUR_API_KEY',
'action' => 'add',
'service' => 8109,
'link' => 'https://instagram.com/p/AbCdEf',
'quantity' => 100
]));
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($response);
import requests
response = requests.post(
"https://demo.example/api/v2",
json={
"key": "YOUR_API_KEY",
"action": "add",
"service": 8109,
"link": "https://instagram.com/p/AbCdEf",
"quantity": 100
},
timeout=30,
)
response.raise_for_status()
print(response.json())
const response = await fetch("https://demo.example/api/v2", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
"key": "YOUR_API_KEY",
"action": "add",
"service": 8109,
"link": "https://instagram.com/p/AbCdEf",
"quantity": 100
}),
});
console.log(await response.json());
Response
{
"order": 23501
}
- The charge is
price × quantity ÷ 1000, rounded to the panel precision. - A quantity outside the service min/max, or a balance that will not cover the charge, comes back as
{ "error": "..." }and nothing is created — no order, no debit.
Order status
action=statusReturns the charge, start count and remaining quantity for one order.
| Name | Type | Required | Description |
|---|---|---|---|
| key | string | Yes | Your API key |
| action | string | Yes | status |
| order | int | Yes | Order ID |
curl -X POST https://demo.example/api/v2 \
-H "Content-Type: application/json" \
-d '{"key":"YOUR_API_KEY","action":"status","order":23501}'
<?php
$ch = curl_init('https://demo.example/api/v2');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'key' => 'YOUR_API_KEY',
'action' => 'status',
'order' => 23501
]));
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($response);
import requests
response = requests.post(
"https://demo.example/api/v2",
json={
"key": "YOUR_API_KEY",
"action": "status",
"order": 23501
},
timeout=30,
)
response.raise_for_status()
print(response.json())
const response = await fetch("https://demo.example/api/v2", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
"key": "YOUR_API_KEY",
"action": "status",
"order": 23501
}),
});
console.log(await response.json());
Response
{
"order": 23501,
"status": "In progress",
"charge": "3.37",
"start_count": "3572",
"remains": "157",
"currency": "INR"
}
statusis the order state — see the table further down.- An id that is not on your account comes back as
{ "error": "Incorrect order ID" }.
Multiple order status
action=multi statusStatus for up to 100 orders in a single call — the cheapest way to poll.
| Name | Type | Required | Description |
|---|---|---|---|
| key | string | Yes | Your API key |
| action | string | Yes | multi status (multi_status also works) |
| orders | string | Yes | Order IDs separated by commas (max 100) |
curl -X POST https://demo.example/api/v2 \
-H "Content-Type: application/json" \
-d '{"key":"YOUR_API_KEY","action":"multi status","orders":"23501,23502,23503"}'
<?php
$ch = curl_init('https://demo.example/api/v2');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'key' => 'YOUR_API_KEY',
'action' => 'multi status',
'orders' => '23501,23502,23503'
]));
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($response);
import requests
response = requests.post(
"https://demo.example/api/v2",
json={
"key": "YOUR_API_KEY",
"action": "multi status",
"orders": "23501,23502,23503"
},
timeout=30,
)
response.raise_for_status()
print(response.json())
const response = await fetch("https://demo.example/api/v2", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
"key": "YOUR_API_KEY",
"action": "multi status",
"orders": "23501,23502,23503"
}),
});
console.log(await response.json());
Response
{
"23501": {
"status": "Completed",
"charge": "3.37",
"start_count": "3572",
"remains": "0",
"currency": "INR"
},
"23502": {
"status": "In progress",
"charge": "1.12",
"start_count": "980",
"remains": "240",
"currency": "INR"
},
"23503": {
"error": "Incorrect order ID"
}
}
- Keyed by order id at the top level, with no wrapper object.
- An id that is not yours comes back as
{ "error": "Incorrect order ID" }in its own slot — the call itself still succeeds.
Request a refill
action=refillQueues a refill for an order on a refill-enabled service.
| Name | Type | Required | Description |
|---|---|---|---|
| key | string | Yes | Your API key |
| action | string | Yes | refill |
| order | int | No | Order ID — one order |
| orders | string | No | Order IDs separated by commas, instead of order (max 100) |
curl -X POST https://demo.example/api/v2 \
-H "Content-Type: application/json" \
-d '{"key":"YOUR_API_KEY","action":"refill","order":23501}'
<?php
$ch = curl_init('https://demo.example/api/v2');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'key' => 'YOUR_API_KEY',
'action' => 'refill',
'order' => 23501
]));
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($response);
import requests
response = requests.post(
"https://demo.example/api/v2",
json={
"key": "YOUR_API_KEY",
"action": "refill",
"order": 23501
},
timeout=30,
)
response.raise_for_status()
print(response.json())
const response = await fetch("https://demo.example/api/v2", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
"key": "YOUR_API_KEY",
"action": "refill",
"order": 23501
}),
});
console.log(await response.json());
Response
{
"refill": 3
}
- Keep the
refillid — it is whatrefill statustakes. - With
ordersinstead oforderthe response is an array:[{ "order": 23501, "refill": 3 }, { "order": 23502, "refill": { "error": "Incorrect order ID" } }]. - A service with no refill, or a refill window that has already closed, comes back as
{ "error": "..." }.
Refill status
action=refill statusState of a refill request.
| Name | Type | Required | Description |
|---|---|---|---|
| key | string | Yes | Your API key |
| action | string | Yes | refill status (refill_status also works) |
| refill | int | No | Refill ID, as returned by refill |
| refills | string | No | Refill IDs separated by commas, instead of refill (max 100) |
| order | int | No | Order ID — accepted as an alternative to refill |
curl -X POST https://demo.example/api/v2 \
-H "Content-Type: application/json" \
-d '{"key":"YOUR_API_KEY","action":"refill status","refill":3}'
<?php
$ch = curl_init('https://demo.example/api/v2');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'key' => 'YOUR_API_KEY',
'action' => 'refill status',
'refill' => 3
]));
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($response);
import requests
response = requests.post(
"https://demo.example/api/v2",
json={
"key": "YOUR_API_KEY",
"action": "refill status",
"refill": 3
},
timeout=30,
)
response.raise_for_status()
print(response.json())
const response = await fetch("https://demo.example/api/v2", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
"key": "YOUR_API_KEY",
"action": "refill status",
"refill": 3
}),
});
console.log(await response.json());
Response
{
"status": "Completed",
"refill": 3
}
statusis one ofPending,In progress,Completed,RejectedorError.- With
refillsthe response is an array:[{ "refill": 3, "status": "Completed" }, { "refill": 4, "status": { "error": "Incorrect refill ID" } }].
Cancel orders
action=cancelQueues a cancellation request for orders that have not been delivered yet.
| Name | Type | Required | Description |
|---|---|---|---|
| key | string | Yes | Your API key |
| action | string | Yes | cancel |
| orders | string | Yes | Order IDs separated by commas (max 100) |
curl -X POST https://demo.example/api/v2 \
-H "Content-Type: application/json" \
-d '{"key":"YOUR_API_KEY","action":"cancel","orders":"23501,23502"}'
<?php
$ch = curl_init('https://demo.example/api/v2');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'key' => 'YOUR_API_KEY',
'action' => 'cancel',
'orders' => '23501,23502'
]));
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($response);
import requests
response = requests.post(
"https://demo.example/api/v2",
json={
"key": "YOUR_API_KEY",
"action": "cancel",
"orders": "23501,23502"
},
timeout=30,
)
response.raise_for_status()
print(response.json())
const response = await fetch("https://demo.example/api/v2", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
"key": "YOUR_API_KEY",
"action": "cancel",
"orders": "23501,23502"
}),
});
console.log(await response.json());
Response
[
{
"order": 23501,
"cancel": 1
},
{
"order": 23502,
"cancel": {
"error": "Incorrect order status"
}
}
]
- One entry per order, in the order you asked for them. A single
orderis also accepted. - Only
pending,processingandinprogressorders can be cancelled; anything else returns{ "error": "Incorrect order status" }in its own slot. - The request is queued for processing — it is not an instant refund.
Order statuses
| Value | Meaning |
|---|---|
| Pending | Accepted, waiting to be sent to the provider. |
| Processing | Being prepared for delivery. |
| In progress | Delivery is running. |
| Completed | Fully delivered; remains is 0. |
| Partial | Partly delivered; the undelivered part is refunded. |
| Canceled | Cancelled and refunded. |
| Refunded | Charge returned to your balance. |
Errors
| Code | When it happens |
|---|---|
| 200 OK | The normal answer, for both success and failure. Read the body: an error field means the call was refused and nothing was changed. |
| 429 Too Many Requests | Rate limit exceeded — back off and retry. |
| 500 Server Error | Something failed on our side. Safe to retry with backoff. |