Reseller API · v2

One URL, seven actions

The catalogue, orders, refills, cancels and your balance, all from a script. POST form fields or JSON, read JSON back. The shapes below are the ones every panel client already expects, so a script written against another panel usually needs the URL and the key changed and nothing else.

Method
POST only. GET answers 405.
Body
Form fields or a JSON object.
Failures
HTTP 200 with an error key.
Your credentialsSigned out
Endpoint
https://xsmmpanel.uk/api/v2
API key

Sign in and your real key drops into every example on this page. Sign in or open an account.

The key spends your balance without a second check. Treat it like the password. If it ends up somewhere public, regenerate it on your API page and the old one stops working immediately.

Getting started

Two minutes to the first call

Copy your key from the panel above, then run the balance call. It moves no money and touches no order, so it is the safest way to prove the key and the endpoint are right before you point a real script at them.

Request
curl -X POST https://xsmmpanel.uk/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=balance"
Response
{
  "balance": "24.3500",
  "currency": "USD"
}
  • An answer of { "error": "Invalid API key" } means the key is wrong or the account is suspended. It still arrives with HTTP 200.
  • An answer of { "error": "Confirm your email address before using the API" } means the key is right and the address has not been confirmed. Open the link in the signup email and run it again.
  • Anything else and you are through. Head to the service list for the ids you will order against.

Request format

The rules that hold everywhere

PropertyValue
Endpointhttps://xsmmpanel.uk/api/v2
MethodPOST. A GET returns HTTP 405 and { "error": "Use POST. See the documentation at /api" }.
Content typeapplication/x-www-form-urlencoded · application/json
Authkey in the body of every request. No headers, no signatures, no session.
ResponseJSON. Money and counts come back as strings; money carries four decimals.
Ids per call100 for orders, refills and the ids you pass to cancel. Anything past that is dropped without a word.
Request · JSON body
curl -X POST https://xsmmpanel.uk/api/v2 \
  -H "Content-Type: application/json" \
  -d '{"key":"YOUR_API_KEY","action":"status","order":23501}'
  • JSON values are turned into strings before they are read, so "quantity": 1000 and "quantity": "1000" behave identically. Arrays do not survive that trip, which is why comments is one string with newlines rather than a list.
  • key and action are trimmed, and action is lower-cased. Fields you invent are ignored rather than rejected.
  • Send the form encoding if you have a choice. It is what the curl examples on this page use and what most existing panel libraries emit.

Service list

action=services

Every service you can order right now, ordered by id. Anything the network has delisted, or an admin has switched off, is left out of the list rather than returned with a flag.

Request fields
FieldTypeRequiredMeaning
keystringYesYour API key.
actionstringYesservices
Request
curl -X POST https://xsmmpanel.uk/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=services"
Response
[
  {
    "service": 1001,
    "name": "Instagram Followers | Max 50K | Instant | No refill",
    "type": "Default",
    "category": "Instagram Followers",
    "rate": "0.4200",
    "min": "50",
    "max": "50000",
    "refill": false,
    "cancel": false,
    "dripfeed": false
  }
]
  • rate is the price per 1,000 units, as a string with four decimals. min and max are strings too. refill, cancel and dripfeed are real JSON booleans, not 0 and 1.
  • type is one of Default, Custom Comments, Mentions, Package or Subscriptions. Only Custom Comments changes what you send to add.
  • Rates move when the network’s cost moves, so cache the list for minutes, not days. The charge is calculated from the rate at the moment the order lands, not the rate you cached.

Add order

action=add

Takes the money and hands the order to the network network inside the same request. The charge is rate × quantity ÷ 1000 rounded to four decimals, and it has already left your balance by the time the response arrives.

Request fields
FieldTypeRequiredMeaning
keystringYesYour API key.
actionstringYesadd
serviceintegerYesService id from the service list.
linkstringYesThe public page, post or profile URL. It has to parse as http or https; a username on its own is rejected before your balance is touched.
quantityintegerYesUnits to deliver. Must sit between the service’s min and max.
runsintegerNoDrip-feed only. How many runs to split the delivery into, 1 to 100.
intervalintegerNoDrip-feed only. Minutes between runs, 1 to 1440.
commentsstringNoCustom Comments services only, and required for them. One comment per line, separated by newlines. Blank lines are dropped.
Request
curl -X POST https://xsmmpanel.uk/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=add" \
  -d "service=1001" \
  -d "link=https://instagram.com/yourprofile" \
  -d "quantity=1000"
Response
{
  "order": 23501
}
Request · drip-feed
curl -X POST https://xsmmpanel.uk/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=add" \
  -d "service=1088" \
  -d "link=https://instagram.com/p/Cx0abcd/" \
  -d "quantity=250" \
  -d "runs=4" \
  -d "interval=60"
Request · custom comments
curl -X POST https://xsmmpanel.uk/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=add" \
  -d "service=1204" \
  -d "link=https://instagram.com/p/Cx0abcd/" \
  -d "quantity=3" \
  --data-urlencode "comments=Shot of the week
Where was this taken?
Saved for later"
  • With runs, quantity is the amount per run. The drip-feed example above bills 4 × 250 = 1,000 units, and the order reads 1,000 everywhere afterwards.
  • Sending runs or interval to a service with dripfeed: false returns Drip-feed is not available for this service. The order is not created.
  • For Custom Comments, quantity is what you are charged for, not the number of lines you sent. Send as many lines as the quantity you are paying for.
  • In a JSON body, comments is still a single string with \n between lines. Arrays are stringified, not read as a list.
  • order comes back as a JSON number. The single-order refill below returns its id as a string. Parse both rather than assuming a type.
  • If the network is unreachable the order is still created and still charged. It sits at Pending and the sync job forwards it on a retry. If the network rejects it outright, the charge goes straight back to your balance. Either way you get an order id, so treat it as a receipt and poll status rather than as proof of delivery.

Order status

action=status

One order, by id. Orders belonging to another account answer the same way a nonexistent id does, so the endpoint never confirms that someone else's order number is real.

Request fields
FieldTypeRequiredMeaning
keystringYesYour API key.
actionstringYesstatus
orderintegerYesOrder id.
Request
curl -X POST https://xsmmpanel.uk/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=status" \
  -d "order=23501"
Response
{
  "charge": "1.7500",
  "start_count": "4821",
  "status": "In progress",
  "remains": "1200",
  "currency": "USD"
}
  • status is one of Pending, In progress, Processing, Completed, Partial or Canceled. The last three are terminal.
  • charge is what the order cost after settlement, so it drops when an order finishes as a Partial and the undelivered share is refunded. Read it again once the status goes terminal if you are reconciling spend.
  • These figures come from the panel’s copy of the order, refreshed by the sync job rather than fetched from the network on every call. Polling faster than that loop returns the same numbers.

Status for many orders

action=status

Same action, but pass orders instead of order and the response becomes an object keyed by id. Use it instead of a loop; one call replaces a hundred.

Request fields
FieldTypeRequiredMeaning
keystringYesYour API key.
actionstringYesstatus
ordersstringYesOrder ids separated by commas. Everything past the 100th is dropped.
Request
curl -X POST https://xsmmpanel.uk/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=status" \
  -d "orders=23501,23502,23503"
Response
{
  "23501": {
    "charge": "1.7500",
    "start_count": "4821",
    "status": "Completed",
    "remains": "0",
    "currency": "USD"
  },
  "23502": {
    "error": "Incorrect order ID"
  },
  "23503": {
    "charge": "0.8400",
    "start_count": "0",
    "status": "Pending",
    "remains": "2000",
    "currency": "USD"
  }
}
  • A bad id fails inside its own key and the rest of the batch still returns. There is no all-or-nothing behaviour here.
  • Values that are not positive integers are dropped before the query runs, so they get no key in the response at all. Match on the ids you sent, not on the ones you got back.
  • If none of the values parse, the whole response collapses to { "error": "Incorrect order ID" }.
  • Send both order and orders and orders wins.

Create refill

action=refill

Asks the network to top the count back up on a completed order. Refills cost nothing; your balance is not touched.

Request fields
FieldTypeRequiredMeaning
keystringYesYour API key.
actionstringYesrefill
orderintegerNoOne order id. Use this or orders.
ordersstringNoOrder ids separated by commas, up to 100. Changes the response to an array.
Request · one order
curl -X POST https://xsmmpanel.uk/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=refill" \
  -d "order=23501"
Response · one order
{
  "refill": "1"
}
Request · many orders
curl -X POST https://xsmmpanel.uk/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=refill" \
  -d "orders=23501,23502"
Response · many orders
[
  { "order": 23501, "refill": 4 },
  { "order": 23502, "refill": { "error": "Refill is not available for this service" } }
]
  • The order has to be Completed and the service has to carry refill: true. Anything else is refused with the reason in the error string.
  • One refill at a time per order. While one sits at Pending or In progress, a second request returns A refill is already in progress for this order.
  • The single form returns the refill id as a string; the multi form returns it as a number on each row. Keep it either way, since refill_status needs it.

Refill status

action=refill_status

Where a refill got to. Takes one id or a list, and the shape changes with it in the same way status does.

Request fields
FieldTypeRequiredMeaning
keystringYesYour API key.
actionstringYesrefill_status
refillintegerNoOne refill id. Use this or refills.
refillsstringNoRefill ids separated by commas, up to 100. Changes the response to an array.
Request · one refill
curl -X POST https://xsmmpanel.uk/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=refill_status" \
  -d "refill=4"
Response · one refill
{
  "status": "Completed"
}
Request · many refills
curl -X POST https://xsmmpanel.uk/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=refill_status" \
  -d "refills=4,9"
Response · many refills
[
  { "refill": 4, "status": "In progress" },
  { "refill": 9, "status": { "error": "Incorrect refill ID" } }
]
  • A refill is Pending, In progress, Completed or Rejected.
  • In the multi form the error replaces the status value, so status is either a string or an object. Check its type before comparing it.
  • Refills on orders that are not yours read as Incorrect refill ID.

Cancel orders

action=cancel

Stops an order that has not started delivering and returns the full charge to your balance. The response is an array whether you send one id or a hundred.

Request fields
FieldTypeRequiredMeaning
keystringYesYour API key.
actionstringYescancel
ordersstringYesOrder ids separated by commas, up to 100. A single order field works too, and the response shape does not change.
Request
curl -X POST https://xsmmpanel.uk/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=cancel" \
  -d "orders=23501,23502"
Response
[
  { "order": 23501, "cancel": 1 },
  { "order": 23502, "cancel": { "error": "Order can no longer be cancelled" } }
]
  • A success is the number 1, not a message. A failure is an object with an error key on that row.
  • Only services with cancel: true can be cancelled, and only while the count has not moved. Once the network reports a start count and part of the quantity is delivered, the window is shut.
  • Orders already sitting with the network are cancelled there first. If they cannot be reached, the row comes back with Could not reach the network to cancel. Try again in a minute. and nothing is refunded, so a retry cannot double-refund you.

Account balance

action=balance

Your spendable credit. Cheap enough to call before a batch of orders so you can stop before the first Not enough funds.

Request fields
FieldTypeRequiredMeaning
keystringYesYour API key.
actionstringYesbalance
Request
curl -X POST https://xsmmpanel.uk/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=balance"
Response
{
  "balance": "24.3500",
  "currency": "USD"
}
  • Four decimals, always USD. The display currency on your account page converts for reading only; charges, rates and this figure stay in dollars.
  • Credit is bought in the panel, not through the API. There is no top-up action.

Errors

A failure is still a 200

Every failure except a GET comes back with HTTP 200 and a body of { "error": "..." }. A client that only checks the status code will read a rejected order as a placed one. Check for the error key on every response before you touch anything else in it.

Handling it
const res = await fetch("https://xsmmpanel.uk/api/v2", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ key: API_KEY, action: "add", service: 1001,
                         link: "https://instagram.com/yourprofile", quantity: 1000 }),
});

const data = await res.json();   // res.ok is true even on a rejection
if (data.error) throw new Error(data.error);

console.log("order", data.order);
Every message the endpoint returns21
MessageCause
Invalid API keyThe key is missing, does not match an account, or the account is suspended.
Confirm your email address before using the APIThe key is real but the address on the account has never been confirmed. This blocks every action, including balance and services. Open the link in the signup email and retry.
Invalid actionaction is missing or is not one of the seven above. The value is trimmed and lower-cased first, so ADD is fine.
Incorrect service IDNo active service carries that id.
Incorrect linklink did not parse as an http or https URL.
Incorrect quantityQuantity is missing, zero, negative or not a number.
Quantity is below the minimum of NN is that service’s own min, so the message tells you the number to use.
Quantity exceeds the maximum of NSame, against max. Split the job across several orders.
Not enough fundsThe charge is larger than your balance. Nothing is deducted and no order is created.
Drip-feed is not available for this serviceruns or interval was sent to a service with dripfeed: false.
Runs must be between 1 and 100Drip-feed run count is out of range.
Interval must be between 1 and 1440 minutesDrip-feed gap is out of range. 1440 minutes is a day.
This service needs a comment on each lineA Custom Comments service was ordered with comments empty or blank.
Incorrect order IDNo order with that id on your account. Other people's orders answer the same way.
Refill is not available for this serviceThe service carries refill: false.
Refill is only available for completed ordersThe order has not reached Completed yet.
A refill is already in progress for this orderOne open refill per order. Poll refill_status and wait for it to settle.
Incorrect refill IDNo refill with that id against one of your orders.
Cancel is not available for this serviceThe service carries cancel: false.
Order can no longer be cancelledThe order is already closed, or delivery has started.
Could not reach the network to cancel. Try again in a minute.The cancel could not be confirmed upstream. Nothing was refunded, so retrying is safe.
  • Messages are plain English and stable. Match on them if you have to, but prefer branching on which action you called plus the presence of error.
  • Not enough funds deducts nothing and creates nothing. Retrying after a top-up is safe.
  • A response that does not match this page is a bug on our side. Open a ticket with the request body and the response and it gets fixed.
API documentation · Xsmmpanel