Developer documentation

Ship a panel on top of ours

A clean REST API with webhooks, bulk ordering and reseller tooling. Use it to wire MIUMIU into your existing panel or build automation on top.

Introduction

The MIUMIU API exposes everything you can do in the dashboard, placing orders, checking status, listing services and reading your wallet balance, as a clean REST API. All requests and responses are JSON over HTTPS. Base URL: https://api.miumiu.market

Authentication

Authenticate with your API key as a Bearer token in the Authorization header. Generate, label and rotate keys from the dashboard. Each request also increments a per-key rate-limit counter (see Rate limits).

Three accepted ways to pass the key

Authorization: Bearer fb_live_… (recommended), X-Api-Key: fb_live_… (alternative header), or key=fb_live_… as a form/query field for Perfect-Panel-compatible clients. Pick whichever fits your stack, the server treats all three identically.

curl https://api.miumiu.market/v1/reseller/balance \
  -H "Authorization: Bearer fb_live_a1b2c3..."

List services

GET/v1/reseller/services

Returns the full service catalog the caller can order from, with live per-1000 rates, min/max quantities, refill flag and platform identifier. Cache responses for up to five minutes, rates can shift when provider routing changes.

curl https://api.miumiu.market/v1/reseller/services \
  -H "Authorization: Bearer fb_live_•••••"

Get balance

GET/v1/reseller/balance

Returns your current wallet balance, currency, and any pending holds. Useful as a guard before placing a batch of orders so you fail fast client-side instead of after the first INSUFFICIENT_BALANCE.

curl https://api.miumiu.market/v1/reseller/balance \
  -H "Authorization: Bearer fb_live_•••••"

Place an order

POST/v1/reseller/orders

Creates a new order. Charge is taken from your wallet at request time as a HOLD; once dispatched to the provider it becomes a DEBIT. Pass an Idempotency-Key header so retries are safe.

curl -X POST https://api.miumiu.market/v1/reseller/orders \
  -H "Authorization: Bearer fb_live_•••••" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "serviceId": "svc_01ABCDE...",
    "link":      "https://instagram.com/yourbrand",
    "quantity":  1000
  }'

Get an order

GET/v1/reseller/orders/{id}

Returns the current state of one order: status, start count, remains, charge, provider order id, and timestamps. Poll this endpoint OR subscribe to webhooks, webhooks scale better.

StatusMeaning
PENDINGCharged and queued for dispatch.
WAITING_PROVIDERNo eligible provider mapping right now, retrying.
IN_PROGRESSAccepted upstream and currently fulfilling.
PARTIALProvider delivered some but not all; refund queued for the gap.
COMPLETEDFully delivered. Terminal.
CANCELEDCanceled before dispatch; HOLD released. Terminal.
REFUNDEDRefund issued after the fact (manual or auto). Terminal.
FAILEDCould not be fulfilled (provider error, invalid link). Terminal.
curl https://api.miumiu.market/v1/reseller/orders/ord_01ABC... \
  -H "Authorization: Bearer fb_live_•••••"

Get many orders

GET/v1/reseller/orders?ids=...

Bulk status lookup for up to 50 orders at once. Useful to refresh a screen of in-flight orders in a single round-trip. Pass a comma-separated list of order IDs in the `ids` query parameter.

curl 'https://api.miumiu.market/v1/reseller/orders?ids=ord_01A,ord_01B,ord_01C' \
  -H "Authorization: Bearer fb_live_•••••"

Cancel an order

POST/v1/reseller/orders/{id}/cancel

Cancels an order that hasn't started yet. Only valid while the order is in PENDING or WAITING_PROVIDER, once the provider accepts it, cancellation is provider-dependent and may be refused.

curl -X POST https://api.miumiu.market/v1/reseller/orders/ord_01ABC.../cancel \
  -H "Authorization: Bearer fb_live_•••••"

Webhooks

MIUMIU POSTs each event to your configured webhook URL once. Every body carries an HMAC-SHA256 signature derived from your per-key webhook secret in the X-MIUMIU-Signature header. Verify the signature before acting on the payload, anyone can POST to your endpoint, only we can sign it.

EventFired when
order.placedAn order is created (either via API or the dashboard).
order.status_changedAn order transitions between non-terminal statuses.
order.completedAn order reaches COMPLETED, full delivery confirmed.
order.refundedA refund is issued back to your wallet.
wallet.creditedA top-up confirms; balance is now available.
import { createHmac, timingSafeEqual } from 'node:crypto';

/** Verifies an inbound MIUMIU webhook. Reject anything that fails. */
function verifySignature(rawBody, signatureHeader, secret) {
  const expected = createHmac('sha256', secret).update(rawBody).digest('hex');
  const got = Buffer.from(signatureHeader, 'hex');
  const exp = Buffer.from(expected,        'hex');
  return got.length === exp.length && timingSafeEqual(got, exp);
}

// Express-style handler - read raw body (not parsed JSON) for the HMAC.
app.post('/webhooks/MIUMIU', (req, res) => {
  const sig = req.header('x-miumiu-signature');
  if (!verifySignature(req.rawBody, sig, process.env.FB_WEBHOOK_SECRET)) {
    return res.status(401).end();
  }
  const evt = JSON.parse(req.rawBody.toString('utf8'));
  // ... handle evt.event, evt.data ...
  res.status(204).end();
});

Errors

All errors return a JSON envelope: { error: { code, message, details? } }. HTTP status follows REST conventions, 4xx for client errors, 429 for rate-limited, 5xx for our side. The `code` is stable; the `message` is human copy and can change.

CodeHTTPMeaning
BAD_REQUEST400Payload failed schema validation. `details.fields` lists which fields.
UNAUTHORIZED401API key missing, malformed, or revoked.
FORBIDDEN403Key is valid but doesn't have the scope this endpoint requires.
NOT_FOUND404The order, service or resource doesn't exist for this caller.
CONFLICT409The action isn't valid in the current state (e.g. cancel an IN_PROGRESS order).
INSUFFICIENT_BALANCE409Wallet balance is below the order charge. Top up and retry.
RATE_LIMITED429Too many requests on this key. Back off, `details.retryAfterSec` says how long.
UPSTREAM502A downstream provider failed; the request itself was valid. Safe to retry.
# Example: insufficient funds at order placement
{
  "error": {
    "code":    "INSUFFICIENT_BALANCE",
    "message": "موجودی کیف پول کافی نیست"
  }
}

Idempotency

Send an Idempotency-Key header (any opaque string up to 128 chars) on any POST that creates state. We cache the first response for 24 hours, repeat requests with the same key return the original body, status code, and headers. Generate a fresh UUID per logical operation.

curl -X POST https://api.miumiu.market/v1/reseller/orders \
  -H "Authorization: Bearer fb_live_•••••" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7c9a1f-2026-05-31" \
  -d '{"serviceId":"svc_01ABC...","link":"https://x.com/y","quantity":500}'

# Re-running the same command returns the original order, not a new one.

Rate limits

Each API key has a per-minute request budget (default 600/min, configurable per key on Pro and above). Exceeding it returns 429 RATE_LIMITED with a retryAfterSec in `details`. The window is sliding, once a request is outside the 60-second window it stops counting.

Burst-safe retries

On 429, sleep `retryAfterSec` seconds before the next call to the same endpoint. The X-RateLimit-Remaining response header (when present) reflects the current bucket, use it to throttle preemptively rather than reactively.

Need help integrating?

Stuck on the HMAC verification or a 409 you don't recognize? Open a ticket from your dashboard with a delivery ID, we triage API tickets first.

Contact support
Get Started
Ship a panel on top of ours · MIUMIU