Reseller API

One API for orders, wallet and the marketplace

Create orders, follow delivery, read balances and manage listings from your own system. Versioned REST endpoints, keys with scopes, idempotent writes and signed webhooks, on the same engine that powers this storefront.

  • REST /v1, JSON in and out
  • Bearer keys with scopes
  • Idempotency-Key on writes
  • Signed webhooks
  • Reseller plan

How an integration works

Five calls from zero to a delivered order

The API mirrors what the dashboard does, in the same order. Nothing is charged until you create an order, and every write is idempotent.

  1. Create a key

    In your dashboard, pick the scopes the key needs and, optionally, the IPs allowed to use it. The full key is shown once.

  2. Read the catalog

    GET /v1/catalog/services returns every published service with the price already in your account currency and tier.

  3. Preview the quote

    POST /v1/orders/preview validates the link and quantity and returns the exact charge without creating anything.

  4. Create the order

    POST /v1/orders with an Idempotency-Key. The wallet is charged and the order is routed to the supplier with the best measured quality.

  5. Listen for events

    Register an https endpoint and receive signed events for status changes, partial delivery, completion, refunds and refills.

Create an order in one requestbash
curl -X POST https://YOUR-DOMAIN/v1/orders \
  -H "Authorization: Bearer smp_live_xxxxxxxxxx_..." \
  -H "Idempotency-Key: 2b7c1d9e-order-1001" \
  -H "Content-Type: application/json" \
  -d '{"service":"<service_id>","link":"https://instagram.com/p/abc","quantity":1000}'

Replace YOUR-DOMAIN with this storefront’s host, the key with your own and <service_id> with an id from the catalog.

Authentication and limits

Keys you can scope, restrict and rotate

A key is a server-side credential. It never goes into a browser, it carries only the permissions you grant, and you can revoke or rotate it at any time without touching your other keys.

Bearer keys

Send Authorization: Bearer smp_live_… or X-Api-Key. The full key is shown once and only its hash is stored. Up to 20 active keys per account, optional expiry date and one-click rotation.

IP allowlist

Optionally pin a key to up to 20 IP addresses. Requests from any other address are refused with 403 FORBIDDEN.

Rate limit per key

Each key inherits the requests-per-minute limit of your customer tier. Every response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset; over the limit you get 429 with Retry-After.

Limit in force for the Reseller tier1,200 requests per minute

Scopes

Each key carries only the scopes you grant. A call outside its scopes is refused with 403 FORBIDDEN.

ScopeWhat it does
catalog:readList services and prices
orders:readRead orders
orders:writeCreate orders, refill and cancel
wallet:readRead balances
assets:readList your listings and offers
assets:writeCreate and edit listings, verification and availability
transactions:writeRecord handoff steps on deals

On every response

  • X-Request-Id: quote it when you contact support
  • X-Api-Version: the date of the contract you are talking to
  • Cache-Control: no-store, responses are never cached

Idempotency

Retry safely, never double-charge

POST /v1/orders and POST /v1/orders/batch require an Idempotency-Key header of 8 to 120 characters. Repeating a call with the same key returns the same order without charging again. Reusing a key with a different body is refused with 409 IDEMPOTENCY_KEY_REUSE. Inside a batch, each item is keyed by the batch key plus its index.

  • Generate one key per logical order (a UUID is ideal) and store it before sending.
  • On a timeout or network error, resend with the same key: you get the original result.
  • Changed the body? Use a new key. The old one stays bound to the first request.
Error bodyhttp
HTTP/1.1 409 Conflict
X-Request-Id: req_<hex>

{
  "error": {
    "code": "IDEMPOTENCY_KEY_REUSE",
    "message": "..."
  },
  "request_id": "req_<hex>"
}

Endpoints

Everything the storefront can do, over HTTP

All paths live under /v1 on this storefront’s host. Money is always a decimal string with an ISO 4217 currency, never a float. Full request and response schemas are in the OpenAPI file.

OpenAPI spec (YAML)

Catalog

MethodPathScopeWhat it does
GET/v1/catalog/platformscatalog:readPlatforms that currently have published services
GET/v1/catalog/servicescatalog:readServices with the price in your currency and tier; filter by platform
GET/v1/catalog/services/{id}catalog:readOne service with its field schema

Orders

MethodPathScopeWhat it does
POST/v1/orders/previeworders:writeValidate and quote without creating or charging
POST/v1/ordersIdempotency-Key requiredorders:writeCreate an order: charges the wallet and routes to the best supplier
GET/v1/ordersorders:readList orders, newest first, with cursor pagination
POST/v1/orders/batchIdempotency-Key requiredorders:writeUp to 100 orders in one call, each with its own result
GET/v1/orders/{id}orders:readFetch one order by id
POST/v1/orders/{id}/refillorders:writeRequest a refill within the guarantee window
POST/v1/orders/{id}/cancelorders:writeRequest cancellation; refunded once the supplier confirms

Wallet

MethodPathScopeWhat it does
GET/v1/wallet/balancewallet:readBalances per currency: available, cash, bonus and reserved

Assets (sellers)

MethodPathScopeWhat it does
POST/v1/assetsassets:writeCreate a listing draft; it goes live after verification and moderation
GET/v1/assetsassets:readYour listings
PATCH/v1/assets/{id}assets:writeUpdate a listing (full body; If-Match for optimistic locking)
POST/v1/assets/batchassets:writeImport up to 1,000 listings, matched by external_ref
POST/v1/assets/{id}/verifyassets:writeStart (method) or check (verification_id) an ownership verification
POST/v1/assets/{id}/availabilityassets:writeHide or show a listing (not while it is under negotiation)

Offers

MethodPathScopeWhat it does
GET/v1/offersassets:readOffers received on your listings

Transactions

MethodPathScopeWhat it does
POST/v1/transactions/{id}/handofftransactions:writeMark a playbook step, add a secure item or complete the handoff
Response (201)http
HTTP/1.1 201 Created
X-Request-Id: req_<hex>
X-Api-Version: 2026-09-23
RateLimit-Limit: <limit>  RateLimit-Remaining: <n>  RateLimit-Reset: <seconds>

{
  "id": "SMP-7K2Q9XHT",
  "status": "routing",
  "service": "<service_id>",
  "link": "https://instagram.com/p/abc",
  "quantity": 1000,
  "charge": "<decimal>",
  "refunded": "0",
  "currency": "USD",
  "start_count": null,
  "remains": null,
  "delivered": null,
  "refill_until": null,
  "created_at": "2026-09-23T12:00:00.000Z",
  "updated_at": "2026-09-23T12:00:00.000Z"
}

Webhooks

Signed events, delivered until you acknowledge them

Register an https endpoint on a public host and choose the events you want. Every delivery is signed with your endpoint secret, which is shown once when the endpoint is created.

Delivery headershttp
POST /webhooks/orders HTTP/1.1
Content-Type: application/json
Webhook-Id: <event id>
Webhook-Timestamp: 1790000000
Webhook-Signature: t=1790000000,v1=<hex HMAC-SHA256(secret, "1790000000.<body>")>

{ "id": "<event id>", "type": "order.partial", "created_at": "2026-09-23T12:05:00.000Z",
  "data": { "orderId": "SMP-7K2Q9XHT", ... } }
Verify in Node.jsjs
import { createHmac, timingSafeEqual } from 'node:crypto';

export function verifyWebhook(secret, headers, rawBody) {
  const t = headers['webhook-timestamp'];
  const v1 = (headers['webhook-signature'] ?? '')
    .split(',').find((p) => p.startsWith('v1='))?.slice(3) ?? '';
  const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
  const fresh = Math.abs(Date.now() / 1000 - Number(t)) < 300; // 5 minutes
  return fresh && expected.length === v1.length
    && timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}

Verify a signature

  1. Read Webhook-Timestamp (t) and the raw request body exactly as received.
  2. Compute HMAC-SHA256 with your endpoint secret over the string "t.body".
  3. Compare it in constant time with the v1 value of Webhook-Signature.
  4. Reject timestamps older than 5 minutes and deduplicate by Webhook-Id.
  5. Respond 2xx quickly and do the work asynchronously.

Retries and the outbox

Events are written to an outbox in the same database transaction as the change that caused them, so nothing is lost when a delivery fails. Failed deliveries are retried after 1 min, 5 min, 30 min, 2 h, 6 h, 12 h and 24 h before being marked dead.

Events you can subscribe to

  • order.created
  • order.status_changed
  • order.partial
  • order.completed
  • order.refunded
  • order.refill_updated
  • deposit.confirmed
  • offer.created
  • offer.updated
  • reservation.created
  • transaction.updated
  • payout.updated
  • listing.updated
  • dispute.updated

Endpoint rules

  • https:// only, on a public host; private and internal addresses are refused.
  • Subscribe to specific events or to all of them.
  • The signing secret is shown once, at creation.

Compatibility

Add this storefront to any SMM panel

POST /api/v2 implements the common “SMM API v2” contract: send key and action as form fields or JSON. Same keys, scopes and rate limits as /v1; only the format changes, and errors come back as { "error": "message" }.

Supported actions

  • services: the catalog with rate, min, max and refill/cancel flags
  • add: create an order (service, link, quantity, comments, usernames, runs, interval)
  • status: one order, or up to 100 with orders=id1,id2
  • balance: available balance in your account currency
  • refill: request refills for one or more orders
  • refill_status: status of one or more refills
  • cancel: request cancellation for one or more orders

Panels do not send an idempotency key, so one is derived from the order content and the current minute; the duplicate-order window covers the rest.

Requestbash
curl -X POST https://YOUR-DOMAIN/api/v2 \
  -d key=smp_live_xxxxxxxxxx_... \
  -d action=add \
  -d service=<service_id> \
  -d link=https://instagram.com/p/abc \
  -d quantity=1000

{ "order": "SMP-7K2Q9XHT" }

Errors

One shape for every error

Every non-2xx response has the same body. Integrate on the code, not on the message: messages may change, codes will not. The request_id is also sent as the X-Request-Id header.

Error bodyhttp
HTTP/1.1 400 Bad Request
X-Request-Id: req_<hex>

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid request.",
    "details": {
      "fields": [{ "path": "quantity", "message": "..." }]
    }
  },
  "request_id": "req_<hex>"
}
CodeHTTPMeaning
VALIDATION_ERROR400Invalid body or headers; details.fields lists each path and problem
UNAUTHORIZED401Missing, invalid, revoked or expired key
INSUFFICIENT_FUNDS402Wallet balance too low for the quote
FORBIDDEN403Key lacks the scope, IP not allowed, sub-user without permission or account suspended
NOT_FOUND404Order, service or listing does not exist for this account
CONFLICT409State conflict, such as the active-keys limit
INVALID_TRANSITION409The order or deal cannot move to that state
DUPLICATE_ORDER409Same service, link and quantity inside the duplicate window
IDEMPOTENCY_KEY_REUSE409Idempotency-Key already used with a different body
ALREADY_RESERVED409The asset is reserved by another buyer
POLICY_BLOCKED422Service or country blocked by platform policy
MARGIN_GUARD422No supplier can serve this order at the published price
UNPROCESSABLE422The request is valid but cannot be fulfilled
RATE_LIMITED429Per-key limit reached; wait the seconds in Retry-After
INTERNAL500Unexpected error; contact support with the request_id
PROVIDER_ERROR502Upstream supplier failure; the order is retried or refunded
NO_ROUTE503No supplier route available right now; retry later
NOT_CONFIGURED503Feature not configured on this storefront

Who can use it

Available on the Reseller plan

API keys and webhook endpoints are created by the account owner on the Reseller plan. Orders placed with a key are charged to the account wallet and appear in the same dashboard as manual orders. Sub-users cannot create keys.

Building a reseller integration on the SocialMediaPRO API

Whether you run a panel that needs a reliable supplier, an agency tool that places orders for clients, or a seller inventory that must stay in sync with the marketplace, the integration follows the same pattern: a scoped key, idempotent writes, and events you verify before you trust them.

One contract, versioned by date

Every endpoint lives under /v1 on the host of the storefront you are integrating with. Responses are JSON, money is a decimal string paired with an ISO 4217 currency, and timestamps are ISO 8601. Each response carries an X-Api-Version header with the date of the contract you are talking to, and an X-Request-Id you can quote to support. Errors always have the same body: an error object with a stable code, a human message and optional details, plus the request_id.

The OpenAPI 3.1 file describes every path, schema and error code. Import it into your HTTP client or generator and you get typed requests for the catalog, orders, wallet, listings, offers and deal handoffs.

Keys, scopes and the account they act for

A key is created by the account owner on the Reseller plan and is shown once; only a hash is stored. When you create it, you choose its scopes, an optional IP allowlist of up to 20 addresses and an optional expiry. Rotation creates a fresh key with the same scopes and revokes the old one, so you can roll credentials without downtime. Orders placed with a key are charged to the account wallet and appear in the same dashboard as manual orders, with their source marked as API.

Each key inherits the requests-per-minute limit of the account’s customer tier. The RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset headers tell you where you stand; when you exceed the limit the API returns 429 with a Retry-After header, and the right response is to wait exactly that long.

Idempotent writes and batches

Order creation is the only call that moves money, so it is protected twice. First, the Idempotency-Key header is mandatory: repeating a request with the same key returns the original order without a second charge, and reusing the key with a different body is refused with 409 IDEMPOTENCY_KEY_REUSE. Second, a duplicate-order window catches the same service, link and quantity sent again inside a short interval without a key match, returning 409 DUPLICATE_ORDER.

Batches accept up to 100 orders per call. Each item is validated and charged on its own, keyed by the batch key plus its index, and the response lists a result per item so one bad line never blocks the rest. Use POST /v1/orders/preview first when you want the exact charge and validation result without creating anything.

  • Generate a UUID per logical order and persist it before sending.
  • On timeouts, resend with the same key; never generate a new one for the same order.
  • Treat 4xx codes as final and 5xx codes and 429 as retryable with backoff.

Webhooks you can trust

Every state change is written to an outbox in the same database transaction as the change itself, and a dispatcher delivers it to your https endpoint with three headers: Webhook-Id, Webhook-Timestamp and Webhook-Signature. The signature is an HMAC-SHA256 of the timestamp, a dot and the raw body, computed with the endpoint secret shown once at creation. Verify it in constant time, reject timestamps older than five minutes and deduplicate by Webhook-Id, because a retried event carries the same id.

Deliveries that do not receive a 2xx are retried after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours, 12 hours and 24 hours before being marked dead. Respond quickly and process asynchronously; a slow handler is the most common reason for duplicate processing.

Child panels through the SMM v2 endpoint

If your panel already speaks the widespread “SMM API v2” format, you can add this storefront as a supplier by pasting the /api/v2 URL and your key. The actions services, add, status, balance, refill, refill_status and cancel are supported, prices come back in your account currency and tier, and errors use the flat { "error": "message" } shape those panels expect. Idempotency is derived from the order content and the current minute, so accidental double submissions inside the same minute are collapsed.

Frequently asked questions

Which plan do I need to use the API?

The Reseller plan. API keys and webhook endpoints are created by the account owner; sub-users cannot create them. Keys are server-side credentials and should never be embedded in a browser or mobile app.

How do I authenticate a request?

Send the key as Authorization: Bearer smp_live_… or in an X-Api-Key header. The key must carry the scope the endpoint requires, for example orders:write to create an order or catalog:read to list services.

What happens if my request times out after creating an order?

Resend it with the same Idempotency-Key. You receive the original order and nothing is charged twice. If you send a different body under the same key, the API answers 409 IDEMPOTENCY_KEY_REUSE.

How do I verify a webhook?

Compute HMAC-SHA256 with your endpoint secret over the string formed by Webhook-Timestamp, a dot and the raw body, then compare it in constant time with the v1 value in Webhook-Signature. Reject timestamps older than 5 minutes and deduplicate by Webhook-Id.

What is the rate limit?

Each key inherits the requests-per-minute limit of your customer tier, shown on this page. The RateLimit-* headers report the current window and a 429 response includes Retry-After in seconds.

Are prices in the API the same as on the site?

Yes. GET /v1/catalog/services returns the price already converted to your account currency with your tier discount, and POST /v1/orders/preview returns the exact charge, including volume discounts and coupons, before you commit.

Can I use the API for marketplace listings?

Yes. With the assets:write scope you can create and update listings, import up to 1,000 at once, start ownership verification and toggle availability; assets:read lists your listings and offers, and transactions:write records handoff steps on a deal.

Ready to integrate?

On the Reseller plan, create a key, download the OpenAPI file and send your first order from your own system.

We never sell reviews or ratings. Some platforms restrict engagement services or account transfers in their terms; you are responsible for the rules of each platform you use.