OTPGet API Docs –
SMS OTP, Rental & Email
Buy virtual phone numbers for OTP verification, rent long-term SMS numbers across 200+ countries, and get temporary Gmail addresses — all via one simple REST API.
All requests must include your API Key in the query string.
The three APIs use different response formats. Make sure your code handles each correctly.
handler_api.php
PLAIN TEXT
ACCESS_NUMBER:abc123:9230012345
STATUS_OK:847293
STATUS_WAIT_CODE
BAD_KEY
Most actions: plain text. Exception: getCountries + getServices return JSON. Use strpos() / explode(":") for plain text.
rental-handler.php
JSON
"status": "200",
"message": "...",
... data fields
}
Check status === "200" for success. Errors have a message field.
email_handler.php
JSON
"status": "200",
"message": "...",
... data fields
}
Check status === "200" for success. 202 = waiting. 300 = cancelled.
Base URL: https://www.otpget.com/stubs/handler_api.php
| # | Action | Key Params | Description |
|---|---|---|---|
| 1 | getBalance | — | Get wallet balance |
| 2 | getCountries | type | List countries by provider (1–5) |
| 3 | getServices | country, type | List services for a country |
| 4 | getNumber | service, country, type | Buy a virtual number for OTP |
| 5 | getStatus | id | Poll for received SMS code |
| 6 | setStatus | id, status | Complete (3 or 6 — needs OTP) or cancel & refund (8 — after 2 min, no OTP) |
Check your account balance in PKR. Returns plain text: ACCESS_BALANCE:500.00
echo file_get_contents($url);
url = "https://www.otpget.com/stubs/handler_api.php"
params = {"api_key": "YOUR_API_KEY", "action": "getBalance"}
print(requests.get(url, params=params).text)
List all available countries. You can filter by provider type (1, 2, 3, 4, or 5).
echo file_get_contents($url);
url = "https://www.otpget.com/stubs/handler_api.php"
params = {"api_key": "YOUR_API_KEY", "action": "getCountries", "type": "1"}
print(requests.get(url, params=params).text)
"1": [
{"id": "33", "name": "Canada"},
{"id": "15", "name": "England"},
{"id": "21", "name": "India"},
{"id": "6", "name": "Indonesia"},
{"id": "61", "name": "Pakistan"},
{"id": "5", "name": "Philippines"},
{"id": "12", "name": "USA"},
{"id": "10", "name": "Vietnam"},
... 30+ more countries
],
"2": [ ... Provider 2 countries ... ],
"3": [ ... Provider 3 countries ... ],
"4": [ ... Provider 4 countries ... ]
}
Get available services for a specific country and provider.
echo file_get_contents($url);
url = "https://www.otpget.com/stubs/handler_api.php"
params = {"api_key": "YOUR_API_KEY", "action": "getServices", "country": "61", "type": "1"}
print(requests.get(url, params=params).text)
"101": "Telegram - 45 PKR",
"102": "WhatsApp - 60 PKR",
"103": "Instagram - 55 PKR"
}
Order a new phone number to receive SMS. This will deduct PKR from your balance.
| Parameter | Type | Description |
|---|---|---|
| service | string | Numeric DB ID from getServices e.g. 101, 102 |
| country | int | Country ID from getCountries — e.g. 61 (Pakistan), 12 (USA), 21 (India) |
| type | int | Provider (1–5) |
echo file_get_contents($url);
url = "https://www.otpget.com/stubs/handler_api.php"
params = {"api_key": "YOUR_API_KEY", "action": "getNumber", "service": "101", "country": "61", "type": "1"}
print(requests.get(url, params=params).text)
ACCESS_NUMBER:order_id:phone_number
Check if an SMS has been received for an order ID.
echo file_get_contents($url);
url = "https://www.otpget.com/stubs/handler_api.php"
params = {"api_key": "YOUR_API_KEY", "action": "getStatus", "id": "abc123xyz"}
print(requests.get(url, params=params).text)
STATUS_WAIT_CODE
STATUS_OK:$code
Complete a successful activation (status 3 or 6 — OTP must already be received), or cancel for a refund (status 8 — only after 2 minutes, no OTP received).
echo file_get_contents($url);
url = "https://www.otpget.com/stubs/handler_api.php"
params = {"api_key": "YOUR_API_KEY", "action": "setStatus", "id": "abc123xyz", "status": "8"}
print(requests.get(url, params=params).text)
| Status Code | Meaning |
|---|---|
| 3 | Complete Activation (Success — OTP must already be received) |
| 6 | Complete Activation (Success — OTP must already be received) |
| 8 | Cancel and Refund — only allowed after 2 minutes from purchase, and only if no SMS received yet |
Balance refunded
NO_SMS_RECEIVED
STATUS_ALREADY_CHANGED
Base URL: https://www.otpget.com/stubs/rental-handler.php
| # | Action | Required Params | Description |
|---|---|---|---|
| 1 | getRentalCountries | — (optional: provider) | List all countries available for rental |
| 2 | getRentalPricing | country_code, provider | Get pricing tiers for a country |
| 3 | getAvailableRentals | country_code, provider | Live stock availability check |
| 4 | rentNumber | country_code, provider, duration_hours | Buy a rental number |
| 5 | getMyRentals | — | List all your rentals |
| 6 | getRentalSMS | order_id | Fetch SMS messages on a rented number |
| 7 | renewRental | rental_id, duration_hours | Extend rental period |
provider=1 = Server 1 | provider=2 = Server 2duration_hours values:
12 = 12 Hours · 24 = 1 Day · 168 = 1 Week · 720 = 1 Month · 4320 = 6 Months · 8640 = 12 Months
List all countries available for rental. Filter by provider or omit to get all servers.
| Parameter | Required | Description |
|---|---|---|
| provider | Optional | 1 = Server 1 | 2 = Server 2. Omit to get both. |
$data = json_decode(file_get_contents($url), true);
foreach($data['countries'] as $c) {
echo $c['name'] . ' (' . $c['country_code'] . ')' . PHP_EOL;
}
r = requests.get("https://www.otpget.com/stubs/rental-handler.php", params={"api_key":"YOUR_API_KEY","action":"getRentalCountries","provider":"2"})
for c in r.json()['countries']:
print(c['name'], c['country_code'])
{"id":"1","provider":"2","name":"Canada","country_code":"ca"},
{"id":"2","provider":"2","name":"UNITED KINGDOM","country_code":"gb"},
{"id":"6","provider":"2","name":"United States of America","country_code":"us"}
]}
Get all available pricing tiers for a country. Use duration_hours from this response when buying or renewing.
| Parameter | Required | Description |
|---|---|---|
| country_code | Required | Country code from getRentalCountries e.g. ca, us |
| provider | Required | 1 = Server 1 | 2 = Server 2 |
$data = json_decode(file_get_contents($url), true);
foreach($data['pricing'] as $p) {
echo $p['duration_hours'] . 'h — ' . $p['price'] . ' PKR' . PHP_EOL;
}
r = requests.get("https://www.otpget.com/stubs/rental-handler.php", params={"api_key":"YOUR_API_KEY","action":"getRentalPricing","country_code":"ca","provider":"2"})
for p in r.json()['pricing']:
print(p['duration_hours']+'h —', p['price'], 'PKR')
{"id":"1","duration_hours":"720","duration_preset":"oneMonth","price":"840.00","country_name":"Canada"},
{"id":"2","duration_hours":"4320","duration_preset":"sixMonths","price":"5040.00","country_name":"Canada"},
{"id":"3","duration_hours":"8640","duration_preset":"twelveMonths","price":"10080.00","country_name":"Canada"}
]}
Check live stock availability for a country before buying. Returns available numbers. Note: Server 2 includes a min_month field — minimum required rental duration in months.
| Parameter | Required | Description |
|---|---|---|
| country_code | Required | e.g. ca, us, gb |
| provider | Required | 1 = Server 1 | 2 = Server 2 |
$data = json_decode(file_get_contents($url), true);
foreach($data['available'] as $a) {
echo $a['area_title'] . ': ' . $a['available'] . ' numbers available' . PHP_EOL;
}
r = requests.get("https://www.otpget.com/stubs/rental-handler.php", params={"api_key":"YOUR_API_KEY","action":"getAvailableRentals","country_code":"ca","provider":"2"})
for a in r.json()['available']:
print(a['area_title'], a['available'], 'available')
{"area_code":"ca","area_title":"Canada","unit_price":200,"available":3338,"min_month":1}
]}
Purchase a phone number for rental. All three parameters are required. Check getRentalPricing first to confirm valid duration_hours values for your country.
| Parameter | Required | Description |
|---|---|---|
| country_code | Required | Country code e.g. ca, us, gb |
| provider | Required | 1 = Server 1 | 2 = Server 2 |
| duration_hours | Required | Rental duration: 12, 24, 168, 720, 4320, 8640 |
$data = json_decode(file_get_contents($url), true);
if($data['status'] == '200') {
echo 'Phone: ' . $data['phone'] . PHP_EOL;
echo 'Order ID: ' . $data['order_id'] . PHP_EOL;
echo 'Expires: ' . $data['expires'] . PHP_EOL;
echo 'Balance: ' . $data['new_balance'] . ' PKR' . PHP_EOL;
}
r = requests.get("https://www.otpget.com/stubs/rental-handler.php", params={
"api_key":"YOUR_API_KEY","action":"rentNumber",
"country_code":"ca","provider":"2","duration_hours":"720"
})
d = r.json()
if d['status'] == '200':
print('Phone:', d['phone'], '| Expires:', d['expires'])
"phone":"3434337545","order_id":"2673093356180000583",
"server":"Server 2","duration_hours":720,
"price_paid":"840.00","new_balance":"4220.00",
"expires":"2026-04-09 21:55:55"}
order_id to fetch SMS later. Save id from getMyRentals to renew.
List all your rented numbers — active and expired. Use order_id to fetch SMS. Use id to renew.
$data = json_decode(file_get_contents($url), true);
foreach($data['rentals'] as $r) {
echo $r['phone_number'] . ' | ' . $r['status'] . ' | expires: ' . $r['expiry_time'] . PHP_EOL;
// use $r['id'] for renewRental
// use $r['order_id'] for getRentalSMS
}
r = requests.get("https://www.otpget.com/stubs/rental-handler.php", params={"api_key":"YOUR_API_KEY","action":"getMyRentals"})
for rental in r.json()['rentals']:
print(rental['phone_number'], rental['status'], rental['expiry_time'])
"id":"27",
"server":"Server 2",
"phone_number":"3434337545",
"order_id":"2673093356180000583",
"status":"active",
"country_code":"ca",
"country_name":"Canada",
"duration_hours":"720",
"price_paid":"840.00",
"expiry_time":"2026-04-09 21:55:55"
}]}
Fetch all SMS messages received on a rented number. Use order_id from rentNumber or getMyRentals.
| Parameter | Required | Description |
|---|---|---|
| order_id | Required | The order_id from rentNumber or getMyRentals |
$data = json_decode(file_get_contents($url), true);
foreach($data['messages'] as $msg) {
echo 'From: ' . $msg['from'] . PHP_EOL;
echo 'Code: ' . $msg['code'] . PHP_EOL;
echo 'Text: ' . $msg['text'] . PHP_EOL;
}
r = requests.get("https://www.otpget.com/stubs/rental-handler.php", params={"api_key":"YOUR_API_KEY","action":"getRentalSMS","order_id":"2673093356180000583"})
for msg in r.json()['messages']:
print('Code:', msg['code'], '| Text:', msg['text'])
"from":"Server 2",
"text":"<#> Your WhatsApp Business code 740-279",
"code":""
"timestamp":"2026-03-09T20:57:32Z"
}]}
Extend the rental period on an active number. Use id from getMyRentals as rental_id. The new expiry is calculated from the current expiry time (not today).
| Parameter | Required | Description |
|---|---|---|
| rental_id | Required | The id field from getMyRentals |
| duration_hours | Required | Extension duration: 12, 24, 168, 720, 4320, 8640 |
$data = json_decode(file_get_contents($url), true);
if($data['status'] == '200') {
echo 'New expiry: ' . $data['new_expiry'] . PHP_EOL;
echo 'New balance: ' . $data['new_balance'] . ' PKR' . PHP_EOL;
}
r = requests.get("https://www.otpget.com/stubs/rental-handler.php", params={"api_key":"YOUR_API_KEY","action":"renewRental","rental_id":"5","duration_hours":"720"})
d = r.json()
if d['status'] == '200':
print('New expiry:', d['new_expiry'], '| Balance:', d['new_balance'])
"rental_id":27,
"phone_number":"3434337545",
"duration_hours":720,
"price_paid":"840.00",
"new_balance":"3440.00","new_expiry":"2026-05-09 21:55:55"}
Buy temporary email addresses from services like Gmail, Telegram, Instagram and 60+ others. All email endpoints use the same base URL below.
Returns all available email services with their names, prices (in your account currency), and current stock count. Optionally filter by domain.
| Parameter | Type | Description |
|---|---|---|
| domain | string | Optional. Email domain to filter. Default: gmail.comOptions: gmail.com · mailnestpro.com · hihinail.com · flytempbox.com · mailburstx.com (contact admin for full list) |
$response = file_get_contents($url);
$data = json_decode($response, true);
foreach($data['services'] as $svc) {
echo $svc['service_name'] . ' — ' . $svc['price'] . ' (stock: ' . $svc['count'] . ')' . PHP_EOL;
}
url = "https://www.otpget.com/stubs/email_handler.php"
params = {"api_key": "YOUR_API_KEY", "action": "getEmailServices", "domain": "gmail.com"}
data = requests.get(url, params=params).json()
for svc in data['services']:
print(svc['service_name'], '-', svc['price'])
"status": "200",
"count": 65,
"services": [
{"service_code": "ig", "service_name": "Instagram", "price": 120.00, "count": 48},
{"service_code": "tg", "service_name": "Telegram", "price": 95.00, "count": 120},
{"service_code": "fb", "service_name": "Facebook", "price": 110.00, "count": 60},
...
]
}
Purchase a temporary email address for a specific service. The price is deducted from your wallet. Returns the email_id and the actual email address to use.
| Parameter | Type | Description |
|---|---|---|
| service_id | string | Required. The service_code field from getEmailServices e.g. ig, tg, fb |
| domain | string | Optional. Email domain. Default: gmail.com |
$data = json_decode(file_get_contents($url), true);
if($data['status'] == '200') {
echo 'Email: ' . $data['email'] . PHP_EOL;
echo 'Email ID: ' . $data['email_id'] . PHP_EOL;
echo 'Price: ' . $data['price'] . ' | New Balance: ' . $data['balance'];
}
url = "https://www.otpget.com/stubs/email_handler.php"
params = {"api_key": "YOUR_API_KEY", "action": "buyEmail", "service_id": "ig", "domain": "gmail.com"}
data = requests.get(url, params=params).json()
if data['status'] == '200':
print('Email:', data['email'])
print('Email ID:', data['email_id'])
"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
}
"status": "402",
"message": "Insufficient balance. Need: 120.00 — Have: 80.50"
}
Poll this endpoint after buying an email to retrieve the verification code / OTP that arrives in the inbox. Call every 5–10 seconds until a code is received.
| Parameter | Type | Description |
|---|---|---|
| email_id | string | Required. The email_id returned from buyEmail |
// Poll every 5 seconds for up to 2 minutes
for($i = 0; $i < 24; $i++) {
$data = json_decode(file_get_contents($url), true);
if($data['status'] == '200' && !empty($data['messages'])) {
echo 'OTP: ' . $data['messages'][0]['code'];
break;
}
sleep(5);
}
url = "https://www.otpget.com/stubs/email_handler.php"
params = {"api_key": "YOUR_API_KEY", "action": "getEmailCode", "email_id": "7291834"}
for _ in range(24): # poll for 2 minutes
data = requests.get(url, params=params).json()
if data['status'] == '200' and data.get('messages'):
print('OTP:', data['messages'][0]['code'])
break
time.sleep(5)
"status": "200",
"email_id": "7291834",
"messages": [
{
"email": "temp.abc123@gmail.com",
"subject": "Verification Code",
"body": "Your verification code is 847293",
"code": "847293"
}
]
}
200 Code received |
202 Still waiting — keep polling every 5–10s |
300 Cancelled
Cancel an email activation. Behavior depends on whether an OTP was already received:
| Situation | Result |
|---|---|
| OTP already received | Order marked complete — OTP code returned. No refund (job was done). |
| Still waiting for OTP | Activation cancelled on provider + full refund to your wallet. |
| Already cancelled | Returns success (safe to call multiple times). |
| Parameter | Type | Description |
|---|---|---|
| email_id | string | Required. The email_id returned from buyEmail |
$data = json_decode(file_get_contents($url), true);
if ($data['status'] == '200') {
echo $data['message'] . PHP_EOL;
if (isset($data['code'])) echo 'OTP Code: ' . $data['code'] . PHP_EOL;
if (isset($data['refunded'])) echo 'Refunded: ' . $data['refunded'] . PHP_EOL;
if (isset($data['balance'])) echo 'New Balance: ' . $data['balance'] . PHP_EOL;
}
url = "https://www.otpget.com/stubs/email_handler.php"
params = {"api_key": "YOUR_API_KEY", "action": "cancelEmail", "email_id": "7291834"}
data = requests.get(url, params=params).json()
print(data['message'])
if 'code' in data: print('OTP Code:', data['code'])
if 'refunded' in data: print('Refunded:', data['refunded'], '| Balance:', data['balance'])
"status": "200",
"message": "Order completed - OTP was already received",
"code": "847293",
"email": "temp.abc@gmail.com"
}
"status": "200",
"message": "Cancelled and refunded",
"refunded": 120.00,
"balance": 5120.00
}
Retrieve your past email purchases with their status, service used, domain, price and timestamp. Supports pagination.
| Parameter | Type | Description |
|---|---|---|
| page | int | Optional. Page number for pagination. Default: 1. Returns 20 records per page. |
$data = json_decode(file_get_contents($url), true);
echo 'Total orders: ' . $data['total'] . PHP_EOL;
foreach($data['history'] as $h) {
echo $h['email_address'] . ' | ' . $h['service_id'] . ' | ' . $h['status'] . PHP_EOL;
}
url = "https://www.otpget.com/stubs/email_handler.php"
params = {"api_key": "YOUR_API_KEY", "action": "getEmailHistory", "page": "1"}
data = requests.get(url, params=params).json()
print('Total:', data['total'])
for h in data['history']:
print(h['email_address'], '|', h['service_id'], '|', h['status'])
"status": "200",
"total": 42,
"page": 1,
"history": [
{
"email_id": "7291834",
"email_address": "temp.abc123@gmail.com",
"service_id": "ig",
"service_name": "Instagram",
"domain": "gmail.com",
"status": "active",
"code": "",
"price": 120.00,
"created_at": "2026-03-09 14:22:00"
}
]
}
| Status Value | Meaning |
|---|---|
| active | Email is active, still waiting for OTP |
| received | OTP code was received — code field contains it |
| cancelled | Manually cancelled via cancelEmail |
Base URL: https://www.otpget.com/stubs/email_handler.php
| # | Action | Key Params | Description |
|---|---|---|---|
| 13 | getEmailServices | domain | List services + prices + stock |
| 14 | buyEmail | service_id, domain | Buy temp email — returns email_id |
| 15 | getEmailCode | email_id | Poll for OTP (200=got it, 202=waiting, 300=cancelled) |
| 16 | cancelEmail | email_id | Cancel & refund if no OTP yet; complete if OTP received |
| 17 | getEmailHistory | page | Paginated purchase history |
| — | getBalance | — | Wallet balance (works on both APIs) |
Error Codes
All three APIs (SMS OTP, Rental, Email) return consistent JSON error responses. Use the status field to detect errors programmatically.
"status": "401",
"message": "BAD_KEY"
}
| Response | HTTP | When it happens |
|---|---|---|
| BAD_KEY | — | API key missing, invalid or belongs to blocked account |
| ACCOUNT_BLOCKED | — | Your account has been suspended by admin |
| BAD_ACTION | — | Unknown action parameter sent |
| BAD_SERVICE | — | Service code not found for given country/type |
| BAD_COUNTRY | — | Country ID not found or missing |
| BAD_TYPE | — | Provider type must be 1, 2, 3, 4 or 5 |
| BAD_ID | — | Order ID parameter missing on getStatus / setStatus |
| BAD_STATUS | — | Status value not 3, 6 or 8 on setStatus |
| NO_BALANCE | — | Insufficient wallet balance to buy number |
| NO_ACTIVATION | — | Order ID not found or does not belong to you |
| STATUS_WAIT_CODE | — | SMS not received yet — keep polling getStatus |
| STATUS_OK:CODE | — | SMS received — code is after the colon |
| STATUS_CANCEL | — | Activation was cancelled — no SMS available |
| STATUS_ALREADY_CHANGED | — | setStatus already called before for this order — cannot change again |
| EARLY_CANCEL_DENIED | — | Cancel attempted within first 2 minutes of purchase — wait and retry |
| NO_SMS_RECEIVED | — | Tried to complete (status 3/6) but no OTP received yet |
| ERROR_PRICE_CHANGE | — | Provider price increased above your balance — number auto-cancelled, no charge |
| NO_BALANCE_FOR_NEW_PRICE:X | — | Provider quoted a higher price than your balance — number cancelled automatically |
| ERROR_PROVIDER_1..5 | — | Upstream provider returned unexpected response — raw provider response appended after colon |
| status | message | When it happens |
|---|---|---|
| 401 | Invalid API key. | Invalid API key |
| 401 | API key is required. | Empty api_key param |
| 403 | Account is blocked or inactive. | Account suspended |
| 400 | Action parameter is required. | Missing action param |
| 400 | Unknown action: … | Unrecognized action value |
| 400 | country_code is required. / provider is required. | Missing required params on getRentalPricing / getAvailableRentals |
| 400 | duration_hours is required. | Missing duration_hours on rentNumber |
| 400 | Server 2 only supports monthly durations… | Server 2 only accepts 720, 4320, 8640 as duration |
| 404 | No pricing found for country_code=… provider=… duration_hours=… | No pricing exists for the given combination on rentNumber |
| 404 | Rental not found or does not belong to you. | Invalid rental_id on renewRental |
| 404 | No pricing found for this duration. | Duration not available for that country/provider on renewRental |
| 404 | Order not found or access denied. | Wrong order_id on getRentalSMS |
| 402 | Insufficient balance. | Wallet balance too low to rent or renew |
| 503 | Server 1/2 is currently unavailable/disabled. | Provider disabled by admin |
| 502 | Server 1/2 error: … | Upstream rental provider returned an error — message has detail |
| 502 | Provider returned an empty phone number. | Provider gave success response but no phone number — try again |
| 500 | Database error: … | DB transaction failed — balance was not deducted |
| status | message | When it happens |
|---|---|---|
| 401 | BAD_KEY | Invalid or missing API key |
| 403 | ACCOUNT_BLOCKED | Account suspended by admin |
| 400 | BAD_ACTION | Unknown action value |
| 400 | service_id is required | Missing service_id on buyEmail |
| 400 | email_id is required | Missing email_id on getEmailCode / cancelEmail |
| 402 | Insufficient balance. Need: X — Have: Y | Balance too low to buy email |
| 404 | Service not available for this domain | Service/domain combo not offered by provider |
| 404 | No stock available for this service | Provider has 0 emails left for this service |
| 404 | Email activation not found | Wrong email_id or belongs to another user |
| 500 | API connection error | Cannot reach mail API |
| 500 | No email available: … | Api returned error on purchase |
| 500 | Database error. Email cancelled. | DB failed after API success — email auto-cancelled |
| 503 | Email service not configured | Admin has not set the mail API key |
| 503 | Email service is currently disabled | Admin disabled email service temporarily |
| 200 | — | Success on all actions |
| 202 | Waiting for code... | getEmailCode: OTP not arrived yet — keep polling |
| 300 | Cancelled / Cancelled by provider | getEmailCode / cancelEmail: activation was cancelled |