Receive SMS Codes with Python: MarioSMS API Tutorial
If you’re testing sign-up flows, running QA against OTP screens, or automating account provisioning you’re allowed to automate, you’ll want to receive SMS codes from code rather than a dashboard. The MarioSMS REST API is a small, predictable surface: rent a number, poll until the code arrives, done. This guide walks through the whole loop in Python with nothing but requests.
Prerequisites
- A MarioSMS account with some balance (create one here)
- Your API key, from your profile in the app
- Python 3.9+ and
pip install requests
The full endpoint reference lives at app.mariosms.com/api-docs. Everything below authenticates with the X-API-Key header.
Step 1: Check your balance
A quick sanity check that your key works:
import requests
BASE = "https://app.mariosms.com/api/v1"
HEADERS = {"X-API-Key": "your_api_key_here"}
r = requests.get(f"{BASE}/balance", headers=HEADERS)
r.raise_for_status()
print(r.json()) # {"balance": 100.0}
Step 2: Rent a number
An activation is one number rented for one verification. You name the service and the country; the response includes the phone number and an expiry:
r = requests.post(
f"{BASE}/activation",
headers=HEADERS,
json={"country": "us", "service": "tg"}, # Telegram, US number
)
r.raise_for_status()
activation = r.json()
print(activation["phone"]) # e.g. "12025551234"
Service and country codes come from GET /api/v1/services and GET /api/v1/countries, and GET /api/v1/prices returns live prices before you commit.
Step 3: Poll for the code
Paste the number into the sign-up form you’re testing, then poll the activation until its status flips to received:
import time
def wait_for_code(activation_id: str, timeout_s: int = 300) -> str | None:
deadline = time.monotonic() + timeout_s
while time.monotonic() < deadline:
r = requests.get(f"{BASE}/activation/{activation_id}", headers=HEADERS)
r.raise_for_status()
data = r.json()
if data["status"] == "received":
return data["smsCode"] # full text in data["smsText"]
time.sleep(5)
return None
code = wait_for_code(activation["id"])
print("OTP:", code)
A 5-second interval is plenty; most codes land in well under a minute.
Step 4: Cancel if you change your mind
If no SMS has arrived yet, cancelling refunds the full price to your balance:
r = requests.post(f"{BASE}/activation/{activation['id']}/cancel", headers=HEADERS)
print(r.json()) # {"message": "activation cancelled", "refund": 1.32}
You don’t need to handle the no-SMS case yourself: if nothing arrives within the activation window, the platform cancels and refunds automatically. You are only ever charged for codes that actually arrive.
Putting it together
The whole integration is: POST /activation → poll GET /activation/:id → read smsCode. There’s also a compatibility API for tools that already speak the classic handler_api.php protocol; see the API docs for both.
Automation is fine where the underlying activity is fine: QA, app testing, accounts you’re entitled to create. Bulk fake-account farming isn’t; see the acceptable use policy.