Free Numbers Pricing Reviews Feedback Terms & Policy API Docs Blog About
Log in Get Started
Developer Portal v2.0

The future of
OTP verification.

Integrate the world's most reliable virtual, premium (call + SMS), long-term rental & email OTP API — with prices in any currency.

https://meotp.com/stubs/handler_api.php
Authentication

Every request — temp number or rental — must include your API Key in the query string.

?api_key=YOUR_API_KEY
Response Format

Every response is JSON, except the Premium (Call + SMS) handler which uses a short plain-text protocol (shown below). The endpoints use slightly different envelopes, so check which one you're calling:

SMS OTP API — /stubs/handler_api.php

SUCCESS
{ "success": true, "action": "getBalance", "data": { "balance": "125.00" } }
ERROR
{ "success": false, "action": "getBalance", "error": "BAD_KEY", "message": "Invalid API key." }

Rental API — /stubs/rental-handler.php

SUCCESS
{ "status": "200", ...action-specific fields }
ERROR
{ "status": "402", "message": "Insufficient balance." }

Premium (Call + SMS) API — /stubs/premium-handler.php

ACCESS_BALANCE:125.00 # plain text STATUS_OK:123456 | STATUS_WAIT_CODE | STATUS_CANCEL { "1": "Pakistan — from Rs60.00" } # getServers / getServices / getPrice are JSON

HTTP status codes are meaningful on both endpoints too (401 bad key, 402 insufficient balance, 404 not found, 502 upstream error) — but always check the JSON body (success or status) first, not just the HTTP code.

Currency (optional)

All prices and balances are in PKR by default. Add the optional currency parameter to any request to receive amounts converted into another currency. The rates are the same ones used by the website currency converter and are refreshed automatically. Use Get Currencies to see the supported codes.

&currency=USD

How it works

CaseBehaviour
currency missing / empty / PKRNothing changes — amounts are returned in PKR exactly as before.
currency=USD (valid code)Amounts in the response are converted to that currency. Codes are case-insensitive.
Unknown codeActions that return amounts reply with an error (BAD_CURRENCY on the SMS OTP and Premium handlers, status 400 on the JSON endpoints). Actions that carry no amounts ignore the parameter, so a typo can never block a cancel or refund.
DecimalsPKR amounts keep 2 decimals. Converted amounts use 4 decimals so small prices stay accurate.
ChargingDisplay only. Your wallet is always charged, refunded and held in PKR; the converted figure is what the PKR amount is worth at the current rate.

Works on

getBalance, getServices / getCountries, getPrice and the purchase actions of every endpoint: SMS OTP, Premium, Rentals and Email OTP.

Examples

# Balance in USD (SMS OTP handler) https://meotp.com/stubs/handler_api.php?api_key=YOUR_API_KEY&action=getBalance&currency=USD { "success": true, "action": "getBalance", "data": { "balance": "0.4500", "currency": "USD" } }
Get Currencies

Lists every currency you can pass as &currency=, sorted A-Z by name, with the rate of 1 PKR in that currency. The same action exists on every endpoint (handler_api.php, premium-handler.php, rental-handler.php, email-handler.php).

https://meotp.com/stubs/handler_api.php?api_key=YOUR_API_KEY&action=getCurrencies
PHP
cURL
Python
$url = 'https://meotp.com/stubs/handler_api.php?api_key=YOUR_KEY&action=getCurrencies';
$res = json_decode(file_get_contents($url), true);
foreach ($res['data']['currencies'] as $c) echo $c['code'] . ' ' . $c['rate'] . "\n";
curl "https://meotp.com/stubs/handler_api.php?api_key=YOUR_KEY&action=getCurrencies"
import requests
r = requests.get("https://meotp.com/stubs/handler_api.php", params={"api_key": "YOUR_KEY", "action": "getCurrencies"}).json()
print([c["code"] for c in r["data"]["currencies"]])
SUCCESS
{ "success": true, "action": "getCurrencies", "data": { "status": "200", "default": "PKR", "count": 147, "currencies": [ { "code": "AED", "name": "United Arab Emirates dirham", "symbol": "AED", "rate": 0.0131 }, { "code": "USD", "name": "United States dollar", "symbol": "$", "rate": 0.0036 } ] } }

On the other four handlers the same body is returned without the success/data wrapper: { "status": "200", "default": "PKR", "count": 147, "currencies": [ ... ] }

1. Get Balance

Check your account balance in PKR (add &currency=XXX for another currency — see Currency) by entering this URL in your browser.

https://meotp.com/stubs/handler_api.php?api_key=YOUR_API_KEY&action=getBalance
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/handler_api.php?api_key=' . $apiKey . '&action=getBalance';
$res = json_decode(file_get_contents($url), true);
echo $res['data']['balance'];
curl "https://meotp.com/stubs/handler_api.php?api_key=YOUR_KEY&action=getBalance"
import requests
url = "https://meotp.com/stubs/handler_api.php"
params = {"api_key": "YOUR_KEY", "action": "getBalance"}
print(requests.get(url, params=params).json())
SUCCESS
{ "success": true, "action": "getBalance", "data": { "balance": "125.00" } }
2. Get Servers

Lists every server type (1-5) and whether it's currently active — check this before assuming a given type value has any countries/services behind it.

https://meotp.com/stubs/handler_api.php?api_key=YOUR_API_KEY&action=getServers
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/handler_api.php?api_key=' . $apiKey . '&action=getServers';
$res = json_decode(file_get_contents($url), true);
foreach ($res['data'] as $s) { echo $s['name'] . ' — ' . ($s['active'] ? 'active' : 'inactive') . PHP_EOL; }
curl "https://meotp.com/stubs/handler_api.php?api_key=YOUR_KEY&action=getServers"
import requests
url = "https://meotp.com/stubs/handler_api.php"
params = {"api_key": "YOUR_KEY", "action": "getServers"}
print(requests.get(url, params=params).json())
SUCCESS
{ "success": true, "action": "getServers", "data": [
  { "type": "1", "name": "Server 1", "active": true },
  { "type": "2", "name": "Server 2", "active": true },
  { "type": "5", "name": "Server 5", "active": true }
] }
3. Get Countries

List all available countries for temp numbers. You can filter by server type (1-5). See Get Servers below to discover which types are currently active.

https://meotp.com/stubs/handler_api.php?api_key=YOUR_API_KEY&action=getCountries&type=1
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/handler_api.php?api_key=' . $apiKey . '&action=getCountries&type=1';
$res = json_decode(file_get_contents($url), true);
print_r($res['data']);
curl "https://meotp.com/stubs/handler_api.php?api_key=YOUR_KEY&action=getCountries&type=1"
import requests
url = "https://meotp.com/stubs/handler_api.php"
params = {"api_key": "YOUR_KEY", "action": "getCountries", "type": "1"}
print(requests.get(url, params=params).json())
SUCCESS
{
  "success": true,
  "action": "getCountries",
  "data": {
    "1": [{"id": "1", "name": "Russia"}, ...],
    "2": [{"id": "1", "name": "USA"}, ...]
  }
}
4. Get Services

Get available services for a specific country and provider.

https://meotp.com/stubs/handler_api.php?api_key=YOUR_API_KEY&action=getServices&country=1&type=1
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/handler_api.php?api_key=' . $apiKey . '&action=getServices&country=1&type=1';
$res = json_decode(file_get_contents($url), true);
print_r($res['data']);
curl "https://meotp.com/stubs/handler_api.php?api_key=YOUR_KEY&action=getServices&country=1&type=1"
import requests
url = "https://meotp.com/stubs/handler_api.php"
params = {"api_key": "YOUR_KEY", "action": "getServices", "country": "1", "type": "1"}
print(requests.get(url, params=params).json())
SUCCESS
{
  "success": true,
  "action": "getServices",
  "data": [
    { "id": "12", "name": "Telegram", "price": "45.00" },
    { "id": "13", "name": "WhatsApp", "price": "60.00" }
  ]
}
Get Price

Price of ONE service — exactly what getNumber would charge — without buying. Add &currency=XXX for another currency.

ParameterRequiredDescription
serviceRequiredService ID from Services
countryRequiredCountry ID from Countries
typeOptionalServer type 1-5 (default 1)
currencyOptionalReturn amounts in this currency instead of PKR — see Currency
https://meotp.com/stubs/handler_api.php?api_key=YOUR_API_KEY&action=getPrice&service=$SERVICE_ID&country=$COUNTRY_ID&type=$PROVIDER_ID
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/handler_api.php?api_key=' . $apiKey . '&action=getPrice&service=$SERVICE_ID&country=$COUNTRY_ID&type=$PROVIDER_ID';
$res = json_decode(file_get_contents($url), true);
echo $res['data']['price'];
curl "https://meotp.com/stubs/handler_api.php?api_key=YOUR_KEY&action=getPrice&service=$SERVICE_ID&country=$COUNTRY_ID&type=$PROVIDER_ID"
import requests
url = "https://meotp.com/stubs/handler_api.php"
params = {"api_key": "YOUR_KEY", "action": "getPrice", "service": "$SERVICE_ID", "country": "$COUNTRY_ID", "type": "$PROVIDER_ID"}
print(requests.get(url, params=params).text)
SUCCESS
{ "success": true, "action": "getPrice", "data": { "server": "1", "country": "1", "service_id": "35", "service_name": "WhatsApp", "currency": "PKR", "price": "144.00" } }
ERROR
{ "success": false, "action": "getPrice", "error": "NO_SERVICE", "message": "Service not found for this country/type." }
5. Request Number

Order a new phone number to receive SMS. This will deduct PKR from your balance.

https://meotp.com/stubs/handler_api.php?api_key=YOUR_API_KEY&action=getNumber&service=$SERVICE_ID&country=$COUNTRY_ID&type=$PROVIDER_ID
ParameterTypeDescription
servicestringService id from Get Services
countryintCountry/server id from Get Countries
typeintServer type (1-5), default 1
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/handler_api.php?api_key=' . $apiKey . '&action=getNumber&service=$SERVICE_ID&country=$COUNTRY_ID&type=$PROVIDER_ID';
$res = json_decode(file_get_contents($url), true);
if ($res['success']) { echo $res['data']['phone']; }
curl "https://meotp.com/stubs/handler_api.php?api_key=YOUR_KEY&action=getNumber&service=$SERVICE_ID&country=$COUNTRY_ID&type=$PROVIDER_ID"
import requests
url = "https://meotp.com/stubs/handler_api.php"
params = {"api_key": "YOUR_KEY", "action": "getNumber", "service": "1", "country": "1", "type": "1"}
print(requests.get(url, params=params).json())
SUCCESS
{
  "success": true,
  "action": "getNumber",
  "data": { "order_id": "a1b2c3...", "phone": "923001234567", "price": "45.00" }
}
6. Get Activation Status

Check if an SMS has been received for an order ID.

https://meotp.com/stubs/handler_api.php?api_key=YOUR_API_KEY&action=getStatus&id=YOUR_ORDER_ID
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/handler_api.php?api_key=' . $apiKey . '&action=getStatus&id=YOUR_ORDER_ID';
$res = json_decode(file_get_contents($url), true);
echo $res['data']['status'];
curl "https://meotp.com/stubs/handler_api.php?api_key=YOUR_KEY&action=getStatus&id=YOUR_ORDER_ID"
import requests
url = "https://meotp.com/stubs/handler_api.php"
params = {"api_key": "YOUR_KEY", "action": "getStatus", "id": "YOUR_ORDER_ID"}
print(requests.get(url, params=params).json())
WAITING
{ "success": true, "data": { "status": "STATUS_WAIT_CODE" } }
RECEIVED
{ "success": true, "data": { "status": "STATUS_OK", "sms": "123456", "code": "123456", "text": "Your WhatsApp code: 123-456" } }

sms is the code (unchanged); code is the latest code and text is the full message when we have it (otherwise the same as the code). If a number receives several messages, text holds them all. Prefer push? See Webhook.

6b. Get Activation Status V2

Same as getStatus (same id, same waiting / cancelled answers), but a received SMS comes back in a structured form with the latest code and the full message text. Plain getStatus keeps working exactly as before — use whichever you prefer.

https://meotp.com/stubs/handler_api.php?api_key=YOUR_API_KEY&action=getStatusV2&id=YOUR_ORDER_ID
PHP
cURL
Python
$url = 'https://meotp.com/stubs/handler_api.php?api_key=YOUR_KEY&action=getStatusV2&id=YOUR_ORDER_ID';
$res = json_decode(file_get_contents($url), true);
if (isset($res['data']['sms'])) { echo $res['data']['sms']['code']; }
curl "https://meotp.com/stubs/handler_api.php?api_key=YOUR_KEY&action=getStatusV2&id=YOUR_ORDER_ID"
import requests
url = "https://meotp.com/stubs/handler_api.php"
params = {"api_key": "YOUR_KEY", "action": "getStatusV2", "id": "YOUR_ORDER_ID"}
print(requests.get(url, params=params).json())
WAITING / CANCELLED
{ "success": true, "action": "getStatusV2", "data": { "status": "STATUS_WAIT_CODE" } }
RECEIVED
{ "success": true, "action": "getStatusV2", "data": { "verificationType": 2, "sms": { "dateTime": "2025-01-01T12:00:00+05:00", "code": "123456", "text": "Your WhatsApp code: 123-456" } } }

text is the full message when the server delivers it, otherwise the same as code. If a number receives several messages, code is the latest one. A cancelled order answers {"status":"STATUS_CANCEL"} like getStatus.

Webhook — get the SMS pushed to your server (optional)

Webhook or polling — your choice. Instead of polling getStatus / getStatusV2, give us an HTTPS address and we will POST every received SMS to it the moment it arrives. It is optional: if you set nothing, nothing changes — getStatus and getStatusV2 keep working exactly as before, and you can use both together.

Set it up

Dashboard → API Tool page → Webhook: enter your Webhook URL (must be https://, a public address). A Webhook secret is generated for you on first save; use Send test to check your endpoint.

A push is a speed-up, not a guarantee: keep a slow fallback poll (for example every 15–30 seconds) so an order is never missed if a push does not arrive.

What we send

POST with Content-Type: application/json:

{ "event": "sms", "activationId": "ORDER_ID", "number": "15550123891", "service": "WhatsApp", "code": "123456", "text": "Your WhatsApp code: 123-456", "receivedAt": "2026-01-01T12:00:00+00:00" }

activationId is the same order id you got from getNumber. text is the full message when we have it, otherwise the code.

Verify the request

Every request carries X-Webhook-Signature: sha256=<hex> (also sent as X-MeOTP-Signature) — the HMAC-SHA256 of the raw request body using your Webhook secret. Compare it before trusting the call:

// PHP $ok = hash_equals('sha256=' . hash_hmac('sha256', file_get_contents('php://input'), $secret), $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '');

Delivery rules

  • Answer with any 2xx status within a few seconds. Otherwise we retry up to 3 times (immediately, after ~5 s, after ~20 s); if your endpoint keeps failing we only try once per message until it recovers.
  • The same message can in rare cases arrive twice — treat activationId + code as idempotent.
  • HTTPS only. Redirects are not followed. Local / private addresses are rejected.
  • If an order receives a second message, you get a second POST with the new code and text.
7. Set Activation Status

Cancel an activation for a refund or complete a successful one.

https://meotp.com/stubs/handler_api.php?api_key=YOUR_API_KEY&action=setStatus&id=YOUR_ORDER_ID&status=8
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/handler_api.php?api_key=' . $apiKey . '&action=setStatus&id=YOUR_ORDER_ID&status=8';
$res = json_decode(file_get_contents($url), true);
echo $res['data']['status'];
curl "https://meotp.com/stubs/handler_api.php?api_key=YOUR_KEY&action=setStatus&id=YOUR_ORDER_ID&status=8"
import requests
url = "https://meotp.com/stubs/handler_api.php"
params = {"api_key": "YOUR_KEY", "action": "setStatus", "id": "YOUR_ORDER_ID", "status": "8"}
print(requests.get(url, params=params).json())
Status CodeMeaning
3 / 6Complete Activation (Success — only once an SMS/code has been received)
8Cancel and Refund (only allowed 2 minutes after purchase)
SUCCESS
{ "success": true, "action": "setStatus", "data": { "status": "ACCESS_READY" } }
Rental Number API

Long-term numbers you keep for weeks or months, instead of a single OTP. This is a separate endpoint from the SMS OTP API above — same api_key, different base URL and a different response shape.

https://meotp.com/stubs/rental-handler.php

Every response here uses a status string ("200" for success, an error code otherwise) rather than the success/data shape used by the SMS OTP API:

{ "status": "200", ...action-specific fields }
{ "status": "402", "message": "Insufficient balance." }
1. Get Rental Countries

List all countries available for long-term number rentals.

https://meotp.com/stubs/rental-handler.php?api_key=YOUR_API_KEY&action=getRentalCountries
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/rental-handler.php?api_key=' . $apiKey . '&action=getRentalCountries';
$data = json_decode(file_get_contents($url), true);
foreach ($data['countries'] as $c) { echo $c['name'] . ' (' . $c['country_code'] . ')' . PHP_EOL; }
curl "https://meotp.com/stubs/rental-handler.php?api_key=YOUR_KEY&action=getRentalCountries"
import requests
url = "https://meotp.com/stubs/rental-handler.php"
params = {"api_key": "YOUR_KEY", "action": "getRentalCountries"}
print(requests.get(url, params=params).json())
SUCCESS
{"status":"200","countries":[
  {"id":"1","provider":"1","name":"Canada","country_code":"ca"},
  {"id":"3","provider":"1","name":"United States of America","country_code":"us"}
]}
2. Get Rental Pricing

Get all available duration/price tiers for a country.

ParameterRequired
country_codeYes
https://meotp.com/stubs/rental-handler.php?api_key=YOUR_API_KEY&action=getRentalPricing&country_code=us
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/rental-handler.php?api_key=' . $apiKey . '&action=getRentalPricing&country_code=us';
$data = json_decode(file_get_contents($url), true);
foreach ($data['pricing'] as $p) { echo $p['duration_hours'] . 'h — ' . $p['price'] . ' PKR' . PHP_EOL; }
curl "https://meotp.com/stubs/rental-handler.php?api_key=YOUR_KEY&action=getRentalPricing&country_code=us"
import requests
url = "https://meotp.com/stubs/rental-handler.php"
params = {"api_key": "YOUR_KEY", "action": "getRentalPricing", "country_code": "us"}
print(requests.get(url, params=params).json())
SUCCESS
{"status":"200","pricing":[
  {"id":"7","duration_hours":"720","price":"2520.00","country_name":"United States of America"},
  {"id":"8","duration_hours":"4320","price":"15120.00","country_name":"United States of America"}
]}
3. Check Availability

Live stock check for a country before buying.

ParameterRequired
country_codeYes
https://meotp.com/stubs/rental-handler.php?api_key=YOUR_API_KEY&action=getAvailableRentals&country_code=us
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/rental-handler.php?api_key=' . $apiKey . '&action=getAvailableRentals&country_code=us';
echo file_get_contents($url);
curl "https://meotp.com/stubs/rental-handler.php?api_key=YOUR_KEY&action=getAvailableRentals&country_code=us"
import requests
url = "https://meotp.com/stubs/rental-handler.php"
params = {"api_key": "YOUR_KEY", "action": "getAvailableRentals", "country_code": "us"}
print(requests.get(url, params=params).json())
SUCCESS
{"status":"200","country_code":"us","provider":"1","available":[
  {"area_code":"us","area_title":"United States of America","available":3338,"min_month":1}
]}
4. Rent a Number

Purchase a phone number for rental. Check getRentalPricing first to confirm a valid duration_hours.

ParameterRequired
country_codeYes
duration_hoursYes — 720, 4320 or 8640
https://meotp.com/stubs/rental-handler.php?api_key=YOUR_API_KEY&action=rentNumber&country_code=us&duration_hours=720
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/rental-handler.php?api_key=' . $apiKey . '&action=rentNumber&country_code=us&duration_hours=720';
$data = json_decode(file_get_contents($url), true);
if ($data['status'] == '200') { echo 'Phone: ' . $data['phone'] . PHP_EOL . 'Order ID: ' . $data['order_id']; }
curl "https://meotp.com/stubs/rental-handler.php?api_key=YOUR_KEY&action=rentNumber&country_code=us&duration_hours=720"
import requests
url = "https://meotp.com/stubs/rental-handler.php"
params = {"api_key": "YOUR_KEY", "action": "rentNumber", "country_code": "us", "duration_hours": "720"}
print(requests.get(url, params=params).json())
SUCCESS
{"status":"200","message":"Number rented successfully",
 "phone":"3434337545","order_id":"2673093356180000583","server":"Server 1",
 "duration_hours":720,"price_paid":"2520.00","new_balance":"4220.00",
 "expires":"2026-10-02 21:55:55"}
5. Get My Rentals

List all your rented numbers. Use order_id to fetch SMS. Use id to renew.

https://meotp.com/stubs/rental-handler.php?api_key=YOUR_API_KEY&action=getMyRentals
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/rental-handler.php?api_key=' . $apiKey . '&action=getMyRentals';
$data = json_decode(file_get_contents($url), true);
foreach ($data['rentals'] as $r) { echo $r['phone_number'] . ' | ' . $r['status'] . PHP_EOL; }
curl "https://meotp.com/stubs/rental-handler.php?api_key=YOUR_KEY&action=getMyRentals"
import requests
url = "https://meotp.com/stubs/rental-handler.php"
params = {"api_key": "YOUR_KEY", "action": "getMyRentals"}
print(requests.get(url, params=params).json())
SUCCESS
{"status":"200","total":1,"rentals":[{
 "id":"27","server":"Server 1","phone_number":"3434337545",
 "order_id":"2673093356180000583","status":"active",
 "country_code":"us","country_name":"United States of America",
 "duration_hours":"720","price_paid":"2520.00","expiry_time":"2026-10-02 21:55:55"
}]}
6. Get Rental SMS

Fetch all SMS messages received on a rented number. Use order_id from rentNumber or getMyRentals.

ParameterRequired
order_idYes
https://meotp.com/stubs/rental-handler.php?api_key=YOUR_API_KEY&action=getRentalSMS&order_id=YOUR_ORDER_ID
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/rental-handler.php?api_key=' . $apiKey . '&action=getRentalSMS&order_id=YOUR_ORDER_ID';
$data = json_decode(file_get_contents($url), true);
foreach ($data['messages'] as $msg) { echo 'Code: ' . $msg['code'] . ' | Text: ' . $msg['text'] . PHP_EOL; }
curl "https://meotp.com/stubs/rental-handler.php?api_key=YOUR_KEY&action=getRentalSMS&order_id=YOUR_ORDER_ID"
import requests
url = "https://meotp.com/stubs/rental-handler.php"
params = {"api_key": "YOUR_KEY", "action": "getRentalSMS", "order_id": "YOUR_ORDER_ID"}
print(requests.get(url, params=params).json())
SUCCESS
{"status":"200","phone_number":"5812822291","order_id":"...","total":1,"messages":[{
 "from":"Server 1","text":"Your WhatsApp code 740-279","code":"740279","timestamp":"2026-09-02T20:57:32Z"
}]}
7. Renew Rental

Extend the rental period on an active number. Use id from getMyRentals as rental_id.

ParameterRequired
rental_idYes — the id field from getMyRentals
duration_hoursYes
https://meotp.com/stubs/rental-handler.php?api_key=YOUR_API_KEY&action=renewRental&rental_id=27&duration_hours=720
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/rental-handler.php?api_key=' . $apiKey . '&action=renewRental&rental_id=27&duration_hours=720';
$data = json_decode(file_get_contents($url), true);
if ($data['status'] == '200') { echo 'New expiry: ' . $data['new_expiry']; }
curl "https://meotp.com/stubs/rental-handler.php?api_key=YOUR_KEY&action=renewRental&rental_id=27&duration_hours=720"
import requests
url = "https://meotp.com/stubs/rental-handler.php"
params = {"api_key": "YOUR_KEY", "action": "renewRental", "rental_id": "27", "duration_hours": "720"}
print(requests.get(url, params=params).json())
SUCCESS
{"status":"200","message":"Renewed successfully","rental_id":27,
 "phone_number":"3434337545","duration_hours":720,
 "price_paid":"2520.00","new_balance":"1700.00","new_expiry":"2027-04-02 21:55:55"}
8. Cancel Rental

Cancel an active rental for a refund — only available within 20 minutes of purchase. This actually cancels the number with the upstream provider (not just a local flag) — the refund only happens once that succeeds. Use id from getMyRentals as rental_id.

ParameterRequired
rental_idYes — the id field from getMyRentals
https://meotp.com/stubs/rental-handler.php?api_key=YOUR_API_KEY&action=cancelRental&rental_id=27
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/rental-handler.php?api_key=' . $apiKey . '&action=cancelRental&rental_id=27';
$data = json_decode(file_get_contents($url), true);
if ($data['status'] == '200') { echo 'Refunded: ' . $data['refunded']; }
curl "https://meotp.com/stubs/rental-handler.php?api_key=YOUR_KEY&action=cancelRental&rental_id=27"
import requests
url = "https://meotp.com/stubs/rental-handler.php"
params = {"api_key": "YOUR_KEY", "action": "cancelRental", "rental_id": "27"}
print(requests.get(url, params=params).json())
SUCCESS
{"status":"200","message":"Cancelled successfully","rental_id":27,
 "refunded":"2520.00","new_balance":"4220.00"}
EXPIRED WINDOW
{"status":"400","message":"Cancel window expired. Rentals can only be cancelled within 20 minutes of purchase."}
Premium API — Call + SMS Verification

Premium numbers receive the verification code by SMS or by phone call. Same api_key as everywhere else, own base URL and a short plain-text protocol. Catalogue and prices are live; amounts are PKR by default (optional currency — see Currency).

https://meotp.com/stubs/premium-handler.php
ActionParametersResponse
getBalance—ACCESS_BALANCE:125.00
getCurrencies—JSON list of currency codes + rates
getServers—JSON map { "id": "Country — from Rs60.00" }
getServicesserverJSON map { "id": "WhatsApp - Rs120.00" }
getPriceserver, serviceJSON with the exact price of one service
buyNumberserver, serviceorder_id,number,validity_seconds
getStatusidSTATUS_OK:code / STATUS_WAIT_CODE / STATUS_CANCEL
setStatusid, status8 = cancel + refund, 6 = finish

A refund is given only after the cancel is confirmed. Once a code has arrived the order can no longer be cancelled — finish it with status=6. Unclear upstream replies never refund; retry getStatus/setStatus a moment later.

1. Get Servers

Countries available for Premium numbers with the lowest price in each.

ParameterRequiredDescription
currencyOptionalReturn amounts in this currency instead of PKR — see Currency
https://meotp.com/stubs/premium-handler.php?api_key=YOUR_API_KEY&action=getServers
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/premium-handler.php?api_key=' . $apiKey . '&action=getServers';
$res = json_decode(file_get_contents($url), true);
print_r($res);
curl "https://meotp.com/stubs/premium-handler.php?api_key=YOUR_KEY&action=getServers"
import requests
url = "https://meotp.com/stubs/premium-handler.php"
params = {"api_key": "YOUR_KEY", "action": "getServers"}
print(requests.get(url, params=params).text)
SUCCESS
{ "1": "Pakistan — from Rs60.00", "2": "India — from Rs48.00" }
ERROR
NO_SERVERS
2. Get Services

Services (with price) available on one server.

ParameterRequiredDescription
serverRequiredServer ID from Get Servers
currencyOptionalReturn amounts in this currency instead of PKR — see Currency
https://meotp.com/stubs/premium-handler.php?api_key=YOUR_API_KEY&action=getServices&server=1
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/premium-handler.php?api_key=' . $apiKey . '&action=getServices&server=1';
$res = json_decode(file_get_contents($url), true);
print_r($res);
curl "https://meotp.com/stubs/premium-handler.php?api_key=YOUR_KEY&action=getServices&server=1"
import requests
url = "https://meotp.com/stubs/premium-handler.php"
params = {"api_key": "YOUR_KEY", "action": "getServices", "server": "1"}
print(requests.get(url, params=params).text)
SUCCESS
{ "11": "WhatsApp - Rs120.00", "12": "Telegram - Rs72.60" }
ERROR
BAD_SERVER  |  NO_SERVICES
3. Get Price

Exact price of one service without buying.

ParameterRequiredDescription
serverRequiredServer ID
serviceRequiredService ID
currencyOptionalReturn amounts in this currency instead of PKR — see Currency
https://meotp.com/stubs/premium-handler.php?api_key=YOUR_API_KEY&action=getPrice&server=1&service=11
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/premium-handler.php?api_key=' . $apiKey . '&action=getPrice&server=1&service=11';
$res = json_decode(file_get_contents($url), true);
echo $res['price'];
curl "https://meotp.com/stubs/premium-handler.php?api_key=YOUR_KEY&action=getPrice&server=1&service=11"
import requests
url = "https://meotp.com/stubs/premium-handler.php"
params = {"api_key": "YOUR_KEY", "action": "getPrice", "server": "1", "service": "11"}
print(requests.get(url, params=params).text)
SUCCESS
{ "status": "200", "server": "1", "service_id": "11", "service_name": "WhatsApp", "currency": "PKR", "price": "120.00" }
ERROR
NO_SERVICE
4. Buy Number

Buys a number and charges your wallet. The price is taken from the live catalogue; if no number can be delivered you are not charged.

ParameterRequiredDescription
serverRequiredServer ID
serviceRequiredService ID
https://meotp.com/stubs/premium-handler.php?api_key=YOUR_API_KEY&action=buyNumber&server=1&service=11
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/premium-handler.php?api_key=' . $apiKey . '&action=buyNumber&server=1&service=11';
$res = explode(',', file_get_contents($url));
[$orderId, $number, $validity] = $res;
curl "https://meotp.com/stubs/premium-handler.php?api_key=YOUR_KEY&action=buyNumber&server=1&service=11"
import requests
url = "https://meotp.com/stubs/premium-handler.php"
params = {"api_key": "YOUR_KEY", "action": "buyNumber", "server": "1", "service": "11"}
print(requests.get(url, params=params).text)
SUCCESS
1109e9c312c2e81ac484,923000001,1200
ERROR
LOW_BALANCE  |  NO_NUMBERS  |  BAD_SERVICE  |  PROVIDER_NOT_CONFIGURED
5. Get Status

Poll for the code (SMS or call). Poll every 3-5 seconds.

ParameterRequiredDescription
idRequiredorder_id from Buy Number
https://meotp.com/stubs/premium-handler.php?api_key=YOUR_API_KEY&action=getStatus&id=YOUR_ORDER_ID
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/premium-handler.php?api_key=' . $apiKey . '&action=getStatus&id=YOUR_ORDER_ID';
echo file_get_contents($url);
curl "https://meotp.com/stubs/premium-handler.php?api_key=YOUR_KEY&action=getStatus&id=YOUR_ORDER_ID"
import requests
url = "https://meotp.com/stubs/premium-handler.php"
params = {"api_key": "YOUR_KEY", "action": "getStatus", "id": "YOUR_ORDER_ID"}
print(requests.get(url, params=params).text)
SUCCESS
STATUS_WAIT_CODE STATUS_OK:123456 STATUS_CANCEL
ERROR
NO_ACTIVATION  |  BAD_ID
6. Set Status

Cancel (refund) or finish an order.

ParameterRequiredDescription
idRequiredorder_id
statusRequired8 cancel + refund (only before a code arrives) · 6 finish (only after a code)
https://meotp.com/stubs/premium-handler.php?api_key=YOUR_API_KEY&action=setStatus&id=YOUR_ORDER_ID&status=8
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/premium-handler.php?api_key=' . $apiKey . '&action=setStatus&id=YOUR_ORDER_ID&status=8';
echo file_get_contents($url);
curl "https://meotp.com/stubs/premium-handler.php?api_key=YOUR_KEY&action=setStatus&id=YOUR_ORDER_ID&status=8"
import requests
url = "https://meotp.com/stubs/premium-handler.php"
params = {"api_key": "YOUR_KEY", "action": "setStatus", "id": "YOUR_ORDER_ID", "status": "8"}
print(requests.get(url, params=params).text)
SUCCESS
ACCESS_READY # status=8, cancelled and refunded ACCESS_FINISH # status=6, order finished
ERROR
BAD_STATUS # a code already arrived, or the cancel could not be confirmed NO_SMS_RECEIVED # status=6 before any code NO_ACTIVATION
Email OTP API

Temporary email addresses for OTP verification. A third, separate endpoint from SMS OTP and Rental — same api_key, own base URL and response shape.

https://meotp.com/stubs/email-handler.php

Every request needs api_key, action, and server (1 or 2, default 1):

ServerFlow
1Service-based — e.g. Instagram/Telegram codes on gmail.com. Needs service_id + domain.
2Domain-based — e.g. gmail.com, mail.com, gmx.com. Needs domain + site. Supports reorderEmail for a fresh code on the same mailbox.

Response shape, same convention as Rental:

{ "status": "200", ...action-specific fields }
{ "status": "202", "message": "Waiting for code..." }

200 success · 202 still waiting · 300 cancelled · anything else is an error.

1. Get Email Services / Domains

Server 1: services available for a domain. Server 2: domains available for a site.

https://meotp.com/stubs/email-handler.php?api_key=YOUR_API_KEY&action=getEmailServices&server=1&domain=gmail.com
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/email-handler.php?api_key=' . $apiKey . '&action=getEmailServices&server=1&domain=gmail.com';
$data = json_decode(file_get_contents($url), true);
foreach ($data['services'] as $s) { echo $s['service_name'] . ' — ' . $s['price'] . PHP_EOL; }
curl "https://meotp.com/stubs/email-handler.php?api_key=YOUR_KEY&action=getEmailServices&server=1&domain=gmail.com"
import requests
url = "https://meotp.com/stubs/email-handler.php"
params = {"api_key": "YOUR_KEY", "action": "getEmailServices", "server": "1", "domain": "gmail.com"}
print(requests.get(url, params=params).json())
SERVER 1 RESPONSE
{"status":"200","server":1,"count":2,"domain":"gmail.com","services":[{"service_code":"ig","service_name":"Instagram","price":120.00,"count":48},{"service_code":"tg","service_name":"Telegram","price":95.00,"count":120}]}
SERVER 2 RESPONSE
{"status":"200","server":2,"count":2,"site":"telegram.com","domains":[{"domain":"gmail.com","price":15.60,"count":82000},{"domain":"mail.com","price":1.17,"count":990125}]}
Get Price

Price of ONE email product — exactly what buyEmail would charge — without buying.

ParameterRequiredDescription
serverOptional1 or 2 (default 1)
service_idOptionalServer 1 only
domainOptionalDomain (required for Server 2)
currencyOptionalReturn amounts in this currency instead of PKR — see Currency
https://meotp.com/stubs/email-handler.php?api_key=YOUR_API_KEY&action=getPrice&server=1&service_id=ig&domain=gmail.com
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/email-handler.php?api_key=' . $apiKey . '&action=getPrice&server=1&service_id=ig&domain=gmail.com';
$res = json_decode(file_get_contents($url), true);
echo $res['price'];
curl "https://meotp.com/stubs/email-handler.php?api_key=YOUR_KEY&action=getPrice&server=1&service_id=ig&domain=gmail.com"
import requests
url = "https://meotp.com/stubs/email-handler.php"
params = {"api_key": "YOUR_KEY", "action": "getPrice", "server": "1", "service_id": "ig", "domain": "gmail.com"}
print(requests.get(url, params=params).text)
SUCCESS
{ "status": "200", "currency": "PKR", "price": "12.00", ... }
2. Buy Email

Server 1 needs service_id + domain. Server 2 needs domain + site.

https://meotp.com/stubs/email-handler.php?api_key=YOUR_API_KEY&action=buyEmail&server=1&service_id=ig&domain=gmail.com
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/email-handler.php?api_key=' . $apiKey . '&action=buyEmail&server=1&service_id=ig&domain=gmail.com';
$data = json_decode(file_get_contents($url), true);
if ($data['status'] == '200') { echo 'Email: ' . $data['email'] . ' | ID: ' . $data['email_id']; }
curl "https://meotp.com/stubs/email-handler.php?api_key=YOUR_KEY&action=buyEmail&server=1&service_id=ig&domain=gmail.com"
import requests
url = "https://meotp.com/stubs/email-handler.php"
params = {"api_key": "YOUR_KEY", "action": "buyEmail", "server": "1", "service_id": "ig", "domain": "gmail.com"}
print(requests.get(url, params=params).json())
SUCCESS
{"status":"200","message":"Email activated successfully","email_id":"7291834","email":"temp.abc123@gmail.com","service":"Instagram","domain":"gmail.com","price":120.00,"balance":4880.00,"server":1}
ParameterServer 1Server 2
service_idRequired (e.g. ig, tg)Not used
domainOptional (default gmail.com)Required (e.g. gmail.com, mail.com)
siteNot usedOptional — site you're registering on (e.g. telegram.com)
3. Get Email Code

Poll every 5–10 seconds after buying to retrieve the verification code.

https://meotp.com/stubs/email-handler.php?api_key=YOUR_API_KEY&action=getEmailCode&email_id=7291834
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/email-handler.php?api_key=' . $apiKey . '&action=getEmailCode&email_id=7291834';
for ($i=0; $i<24; $i++) {
  $data = json_decode(file_get_contents($url), true);
  if ($data['status']=='200') { echo 'Code: ' . $data['messages'][0]['code']; break; }
  sleep(5);
}
curl "https://meotp.com/stubs/email-handler.php?api_key=YOUR_KEY&action=getEmailCode&email_id=7291834"
import requests
url = "https://meotp.com/stubs/email-handler.php"
params = {"api_key": "YOUR_KEY", "action": "getEmailCode", "email_id": "7291834"}
print(requests.get(url, params=params).json())
WAITING
{"status":"202","message":"Waiting for code..."}
RECEIVED
{"status":"200","email_id":"7291834","server":1,"messages":[{"email":"temp.abc123@gmail.com","code":"740279"}]}
4. Cancel Email

Cancel an activation. If a code already arrived, this completes it instead. If still waiting, it cancels and refunds.

https://meotp.com/stubs/email-handler.php?api_key=YOUR_API_KEY&action=cancelEmail&email_id=7291834
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/email-handler.php?api_key=' . $apiKey . '&action=cancelEmail&email_id=7291834';
echo file_get_contents($url);
curl "https://meotp.com/stubs/email-handler.php?api_key=YOUR_KEY&action=cancelEmail&email_id=7291834"
import requests
url = "https://meotp.com/stubs/email-handler.php"
params = {"api_key": "YOUR_KEY", "action": "cancelEmail", "email_id": "7291834"}
print(requests.get(url, params=params).json())
SUCCESS
{"status":"200","message":"Cancelled and refunded","refunded":120.00,"balance":5000.00}
5. Reorder Email (Server 2 only)

Request a fresh code on the same mailbox — the order stays open, it does not close/finish it. Only for Server 2 emails that already received a code. After a successful reorder the order flips back to "waiting" so you can poll getEmailCode again.

https://meotp.com/stubs/email-handler.php?api_key=YOUR_API_KEY&action=reorderEmail&server=2&email_id=7291834
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/email-handler.php?api_key=' . $apiKey . '&action=reorderEmail&server=2&email_id=7291834';
echo file_get_contents($url);
curl "https://meotp.com/stubs/email-handler.php?api_key=YOUR_KEY&action=reorderEmail&server=2&email_id=7291834"
import requests
url = "https://meotp.com/stubs/email-handler.php"
params = {"api_key": "YOUR_KEY", "action": "reorderEmail", "server": "2", "email_id": "7291834"}
print(requests.get(url, params=params).json())
SUCCESS
{"status":"200","message":"Reordered — waiting for a new code","email_id":"7291834","email":"temp.abc123@gmail.com","server":2}
6. Get Email History

Retrieve your past email purchases. Paginated, 20 per page.

https://meotp.com/stubs/email-handler.php?api_key=YOUR_API_KEY&action=getEmailHistory&page=1
PHP
cURL
Python
$apiKey = 'YOUR_KEY';
$url = 'https://meotp.com/stubs/email-handler.php?api_key=' . $apiKey . '&action=getEmailHistory&page=1';
$data = json_decode(file_get_contents($url), true);
foreach ($data['history'] as $h) { echo $h['email_address'] . ' | ' . $h['status'] . PHP_EOL; }
curl "https://meotp.com/stubs/email-handler.php?api_key=YOUR_KEY&action=getEmailHistory&page=1"
import requests
url = "https://meotp.com/stubs/email-handler.php"
params = {"api_key": "YOUR_KEY", "action": "getEmailHistory", "page": "1"}
print(requests.get(url, params=params).json())
SUCCESS
{"status":"200","total":42,"page":1,"per_page":20,"history":[{"email_id":"7291834","email_address":"temp.abc123@gmail.com","service_name":"Instagram","domain":"gmail.com","status":"received","code":"740279","price":120.00,"server":1,"created_at":"2026-09-02 12:00:00"}]}

Error Codes

SMS OTP API — /stubs/handler_api.php

CodeDescription
BAD_KEYMissing or invalid API key.
ACCOUNT_BLOCKEDThis account is suspended.
BAD_ACTIONMissing or unrecognized action.
BAD_COUNTRY / BAD_SERVICE / BAD_TYPE / BAD_ID / BAD_STATUSA required parameter is missing, invalid, or has no matching record.
BAD_CURRENCYUnknown currency code — see Get Currencies.
NO_SERVICEgetPrice: service not found for this country/type.
NO_BALANCEInsufficient wallet balance for this purchase.
NO_WALLETNo wallet record found for this account.
NO_ACTIVATIONNo activation found for this id on this account.
EARLY_CANCEL_DENIEDNumbers can only be cancelled 2 minutes after purchase.
NO_SMS_RECEIVEDCannot finish the order — no SMS/code received yet.
STATUS_ALREADY_CHANGEDThis activation was already finalized (finished or cancelled).
PROVIDER_NOT_CONFIGUREDThe selected server has no credentials configured on this account.
ERROR_PROVIDER_1-4The upstream server returned an error — see message for details.

Rental API — /stubs/rental-handler.php

statusmessageWhen it happens
401Invalid API key / API key is required.Missing or invalid api_key
403Account is blocked or inactive.Account suspended
400Unknown action / a required param is missing / invalid currency / Cancel window expired.Bad or missing action, country_code, duration_hours, etc. — or cancelRental called more than 20 minutes after purchase
402Insufficient balance.Wallet balance too low
404No pricing found… / Rental not found…No pricing for that country/duration, or wrong rental_id/order_id
503Server 1 is currently unavailable/disabled.Rentals switched off in admin settings
502Server 1 error: …Upstream error — see message
500Database error: …DB transaction failed — balance not deducted

Email OTP API — /stubs/email-handler.php

statusWhen it happens
401Invalid or missing API key
403Account suspended by admin
400Missing/unknown action, or a required param (service_id, domain, email_id) is missing
402Insufficient balance
404Service/domain not available, or email activation not found
500Server 1/2 connection error, or database error
503Email service not configured or disabled
200Success on all actions
202getEmailCode: still waiting — keep polling
300Activation was cancelled (by you or by the provider)

Premium API — /stubs/premium-handler.php

ResponseMeaning
BAD_KEY / ACCOUNT_BLOCKEDInvalid API key / account suspended
BAD_ACTION / BAD_ID / BAD_SERVER / BAD_SERVICE / BAD_STATUSMissing or invalid parameter (BAD_STATUS on setStatus 8 also means a code already arrived or the cancel could not be confirmed)
BAD_CURRENCYUnknown currency code
LOW_BALANCEInsufficient wallet balance
NO_NUMBERS / NO_SERVERS / NO_SERVICES / NO_SERVICENothing available right now (you are not charged)
NO_ACTIVATIONNo order with this id on this account
NO_SMS_RECEIVEDCannot finish — no code yet
PROVIDER_NOT_CONFIGURED / PROVIDER_UNAVAILABLEPremium is switched off or temporarily unreachable
REST API V2.0Quick Ref
Are you a developer?SMS, Premium, Rental & Email OTP API