ResellPortal API

Integrate every white-label service directly into your own application. Create clients, provision services, and manage subscriptions programmatically. This reference is generated from the live platform documentation, so it always matches what your panel shows.

Get your API keys →

Base URL

https://panel.resellportal.com/wp-json/resellportal/v1/

Get your API credentials: log in to your ResellPortal panel and open the API section to view your API Key and API Secret. API access requires a wallet balance of at least $20.

API DocumentationAll API requests require authentication using your API Key and API Secret in the request headers.

Authentication Headers
X-API-Key: your_api_key
X-API-Secret: your_api_secret
Use ResellPortal from Claude, ChatGPT or Cursor (MCP)
Add this address to your AI assistant, sign in with your ResellPortal login and click Allow. It can then check your store, look up wholesale prices, create clients and place orders for you.
https://panel.resellportal.com/mcp
Claude: Settings → Connectors → Add custom connector
ChatGPT: Settings → Apps & Connectors → Advanced → Developer mode → Create (choose OAuth)
Cursor: Add to Cursor or Settings → MCP → Add new server
No account? https://panel.resellportal.com/mcp/public gives the catalog, prices and docs without signing in. Orders and other changes run in test mode unless you ask for a live action; a live order is charged to your wallet and needs enough balance to cover it. Disconnect an app under Profile → Connected Apps.
Global Flags
skip_client_email
Add "skip_client_email": true to any order request to suppress the built-in welcome email. Useful when your CRM handles the credential delivery. The API response still returns the credentials (vpn_credentials, client_credentials, bio, etc.) so you can pass them into your own email flow. Defaults to false.
client_access_url
Every app product's order response includes client_access_url — the absolute, customer-facing URL for that service on your storefront domain (for example https://your-store.com/crm). No ResellPortal domain ever appears. Your client can open it directly with the returned credentials, or sign in once at https://your-store.com/account with the portal_credentials returned by POST /clients and open every service from there. Not returned for fulfilment-only products (SMM, eSIM, domains, WordPress plugins), which have no login.
test_mode
Add "test_mode": true (or send header X-RP-Test-Mode: 1 — accepts 1, true, yes, on) to validate your integration without touching your wallet. Works on POST /orders, POST /clients, DELETE /clients/{id}, and DELETE /services/{id}. The endpoint authenticates, runs product-specific param validation, and returns a realistic mock response shaped like the real one — with a test_svc_* (or test_cli_*) ID and a would_charge field showing what the real call would have deducted. No charge, no real records, no client email. Defaults to false.
GET /balance Get wallet balance
Response:
{
  "success": true,
  "balance": 150.00,
  "currency": "USD"
}
GET /products List available products
Response:
{
  "success": true,
  "products": [
    {
      "id": "ai_receptionist",
      "name": "AI Receptionist",
      "icon": "fa-headset",
      "type": "recurring",
      "category": "digital",
      "pricing": { "chat": 30.00, "booking": 78.00, "phone": 198.00 },
      "wholesale": { "chat": 15.00, "booking": 39.00, "phone": 99.00 }
    }
  ]
}

pricing is what your clients pay on your store (your retail prices). wholesale is what you pay per sale, after your wallet discount. Both are keyed by plan or billing option. Products priced per item (eSIM, social media, domains) show a pricing_note instead.

GET /clients List all clients
Response:
{
  "success": true,
  "clients": [
    {
      "id": 1,
      "name": "John Doe",
      "email": "john@example.com",
      "created_at": "2025-01-15"
    }
  ]
}
GET /clients/{id} Get single client details
Response:
{
  "success": true,
  "client": {
    "id": 123,
    "name": "John Doe",
    "email": "john@example.com",
    "phone": "+1234567890",
    "company": "Acme Inc",
    "source": "api",
    "active_services": 2,
    "total_services": 3,
    "total_revenue": 45.00,
    "created_at": "2025-01-15"
  }
}
POST /clients Create a new client
Request Body:
{
  "name": "John Doe",
  "email": "john@example.com",
  "phone": "+1234567890",
  "company": "Acme Inc",
  "portal_password": "optional - min 8 chars, generated if omitted",
  "send_setup_email": "optional - true to email the client a set-password link instead of returning a password"
}
Response:
{
  "success": true,
  "client_id": 123,
  "message": "Client created successfully",
  "portal_login_url": "https://your-store.com/account",
  "portal_credentials": {
    "email": "john@example.com",
    "password": "Xk9mP2vQ7Lw4"
  },
  "setup_email_sent": false
}
With "send_setup_email": true no password is generated for you: password is null, setup_email_sent is true, and the client receives a branded email with a link (valid 3 days) to choose their own password. Use this when your integration should never see or store client passwords.
portal_credentials is the client's login for your storefront account page, where every service they own opens with one click. It is returned once, at creation — store it or send it to the client. Pass portal_password to set your own.
DELETE /clients/{id} Delete a client
Client must have no services. Delete all services first.
Response:
{
  "success": true,
  "message": "Client deleted successfully"
}
GET /services List all services
Query Parameters: ?status=active (optional)
Response:
{
  "success": true,
  "services": [
    {
      "id": 1,
      "client_id": 123,
      "service_type": "ai_tools",
      "status": "active",
      "monthly_cost": 49.00,
      "next_billing_date": "2025-02-15"
    }
  ]
}
GET /services/{id}/usage eSIM data usage and status
Live data usage for an eSIM service. Works for service_type esim only. Byte fields are exact; total, used and remaining are human-readable. Results are cached for 5 minutes. Returns 409 if the eSIM has not been issued yet and 503 if the carrier has no usage data yet.
Response:
{
  "success": true,
  "service_id": 456,
  "usage": {
    "status": "Active",
    "esim_status": "IN_USE",
    "iccid": "8944...",
    "total_bytes": 5368709120,
    "used_bytes": 1234567890,
    "remaining_bytes": 4134141230,
    "total": "5.00 GB",
    "used": "1.15 GB",
    "remaining": "3.85 GB",
    "pct_used": 23,
    "expires_at": "2026-11-12T00:00:00+00:00"
  },
  "cached_for_seconds": 300
}
GET /orders List all orders with filtering
Query Parameters: ?status=active&product_type=vpn&client_id=123&limit=50&offset=0 (all optional)
Response:
{
  "success": true,
  "orders": [
    {
      "id": 1,
      "client_id": 123,
      "client_name": "John Doe",
      "client_email": "john@example.com",
      "product_type": "vpn",
      "status": "active",
      "deployment_status": "deployed",
      "cost": 6.00,
      "actual_cost": 2.00,
      "billing_cycle": "monthly",
      "next_billing_date": "2026-04-15",
      "purchase_origin": "reseller_panel",
      "created_at": "2026-03-15 10:30:00"
    }
  ],
  "total": 45,
  "limit": 50,
  "offset": 0
}
GET /services/{id} Get single service details
Response:
{
  "success": true,
  "service": {
    "id": 456,
    "client_id": 123,
    "client_name": "John Doe",
    "client_email": "john@example.com",
    "service_type": "web_hosting",
    "status": "active",
    "billing_cycle": "monthly",
    "monthly_cost": 15.00,
    "next_billing_date": "2025-02-15",
    "deployment_status": "deployed",
    "service_data": {
      "username": "johndoe",
      "domain": "example.com"
    },
    "created_at": "2025-01-15"
  }
}
POST /orders Create a new order/subscription
Note: Different products require different parameters. Select a product below to see the request format.
AI Receptionist
Activate a 24/7 AI receptionist for a client's website. plan is required: chat (AI Chat, $15/mo: answers questions, captures leads, inbox, webhooks) booking (Chat + Booking, $39/mo: adds appointment booking with calendar busy-time check, reminders and follow-ups) or phone (Chat + Booking + Phone, $99/mo: also answers the business phone 24/7 with call transfers and spam screening, unlimited calls for normal business use; the client picks their number in the dashboard). Billed monthly. The client sets it up at /receptionist on your storefront; the response includes their install code and shareable chat link. One per client.
Client receives: Branded welcome email with a link to their dashboard and a 4-step setup guide. Pass skip_client_email: true to opt out.
Request:
POST /wp-json/resellportal/v1/orders
Content-Type: application/json

{
  "client_id": 123,
  "product_key": "ai_receptionist",
  "plan": "booking"
}
Parameters:
plan - Required. chat, booking or phone.
skip_client_email - Optional true/false. Skip the built-in welcome email. Default false.
Response:
{
  "success": true,
  "service_id": 2601,
  "message": "AI Receptionist activated successfully",
  "client_access_url": "https://yourstore.com/receptionist",
  "ai_receptionist": {
    "plan": "booking",
    "plan_label": "Chat + Booking",
    "dashboard_url": "https://yourstore.com/receptionist",
    "chat_url": "https://yourstore.com/receptionist/chat/air_k3v9...",
    "embed_code": "<script src=\"https://yourstore.com/receptionist/widget.js\" data-key=\"air_k3v9...\" async></script>"
  },
  "billing_cycle": "monthly",
  "amount_charged": 39,
  "new_balance": 103.50
}
DELETE /services/{id} Delete a service
Response:
{
  "success": true,
  "message": "Service deleted successfully"
}
GET /esim-packages List available E-SIM packages
Query Parameters: ?location=US (optional - filter by country code)
Response:
{
  "success": true,
  "total_packages": 60,
  "packages": [
    {
      "package_code": "PHAJHEAYP",
      "name": "United States 1GB 7Days",
      "price": 1.80,
      "description": "United States 1GB 7Days",
      "location": "US",
      "data_volume": "1 GB",
      "duration": "7 day",
      "speed": "3G/4G/5G"
    }
  ]
}
Use the package_code when creating E-SIM orders. Over 2000+ packages available worldwide.
GET /smm-services List available SMM services
Query Parameters:
?search=instagram - Filter by service name or description
?category=followers - Filter by category
?platform=instagram - Filter by platform (instagram, youtube, tiktok, facebook, twitter, etc.)
?type=followers - Filter by service type (followers, likes, views, comments, shares, etc.)
?country=US - Filter by country code (ISO 3166-1 alpha-2)
?quality=real - Filter by quality tier (real, premium, high_quality, standard, bot, economy)
?refill=true - Filter by refill availability
?min_rate=0.50 - Minimum rate per 1000
?max_rate=5.00 - Maximum rate per 1000
?sort_by=rate - Sort by: rate, name, service_id, min_quantity, max_quantity, platform, category
?sort_order=asc - Sort direction: asc, desc
?page=1 - Page number (requires per_page)
?per_page=50 - Results per page (max 500, omit for all results)
Response:
{
  "success": true,
  "total_services": 150,
  "page": 1,
  "per_page": 50,
  "total_pages": 3,
  "services": [
    {
      "service_id": "1234",
      "name": "Instagram Followers [Real] [USA]",
      "category": "Instagram - Followers",
      "rate_per_1000": 2.50,
      "min_quantity": 100,
      "max_quantity": 50000,
      "platform": "instagram",
      "service_type": "followers",
      "quality_tier": "real",
      "description": "Real Instagram followers from active accounts.",
      "type": "Default",
      "country_code": "US",
      "country_name": "United States",
      "geo_type": "country_targeted",
      "refill": true,
      "cancel": true,
      "drop_rate": "Almost No",
      "start_time": "2 mins",
      "delivery_speed": "12 mins",
      "reliability": "Good",
      "status": "active",
      "tags": ["instagram", "followers", "real", "us", "refill"]
    }
  ]
}
Use the service_id when creating SMM orders. Rate is cost per 1000 units. Pagination fields only appear when per_page is specified.
GET /vpn/servers List VPN server locations (82+, for WireGuard/OpenVPN)
Response:
{ "success": true, "servers": [ { "id": 135, "name": "cz1.ipcover.net", "city": "Prague #1", "country_code": "CZ" } ] }
GET /vpn/ports List OpenVPN ports
Response:
{ "success": true, "ports": [ { "id": 1, "protocol": "udp", "number": 1194, "default": 1 } ] }
GET /vpn/config Get WireGuard/OpenVPN config for a VPN subscription
Query Parameters:
?service_id=597 *required - An active VPN service (from GET /services)
?server_id=135 *required - From GET /vpn/servers
?protocol=wireguard - wireguard (default) or openvpn
?port_id=1 - OpenVPN only, from GET /vpn/ports
Response:
{
  "success": true,
  "protocol": "wireguard",
  "filename": "wg0.conf",
  "config": "[Interface]\nPrivateKey = ...\nAddress = 10.245.77.200/32\nDNS = 172.16.0.1\n\n[Peer]\nPublicKey = ...\nAllowedIPs = 0.0.0.0/0,::/0\nEndpoint = cz1.ipcover.net:55888\n"
}
Embed the returned config in your own app (Capacitor/Android VpnService). Same VPN account works across all servers — just change server_id. WireGuard recommended for streaming.