DaisySMS Alternative: Where to Go Now DaisySMS Has Shut Down
DaisySMS is gone. Its homepage now reads "DaisySMS has shut down on March 26, 2026". New sign-ups and top-ups were switched off on February 24, and only a support email remains. If you relied on it for US verification numbers, or had a script built on its API, you need somewhere else. This page covers what to look for, how SMS Portal compares, and how to move an API integration across call by call.
This page is written by SMS Portal, one of the alternatives. Facts about DaisySMS come from its own shutdown notice and API documentation as of September 2026.
What DaisySMS users actually relied on
DaisySMS was popular for a narrow, specific thing, and a replacement has to match that thing rather than just "sell numbers":
- Real US mobile numbers, not VoIP, so codes from strict platforms actually arrive.
- Carrier and area-code filters. Its API took
carriers=tmo,vz,att,areas=and evennumber=for a specific number. - Your money back when nothing arrived. Cancelling returned the held amount.
- A simple API. The SMS-Activate-compatible
handler_api.phpprotocol, withgetNumber,getStatusandsetStatus. - Keeping a number for later with
action=keep.
How SMS Portal lines up
| What you used on DaisySMS | On SMS Portal |
|---|---|
| Real US mobile numbers | Yes: every number is a US carrier line. What non-VoIP means. |
| Carrier filter | Yes, AT&T or T-Mobile, on the Temp (s2) server. Verizon is not offered. |
| Area-code filter | Yes, on Temp (s2), with live stock per area code shown before you order. Can be a preference or a requirement. |
| Request a specific number | Yes, on Temp (s2) (request-specific-number). |
| Refund when no code arrives | Yes. Cancel before a code arrives and the full price goes back to your balance; unused numbers are refunded automatically at expiry. |
| Keep a number | Rentals of 1, 3, 7, 14 or 30 days, with renewal and auto-renew. Or reuse a one-time number from your order history while it is still available. |
| API | REST + JSON with a bearer token, plus signed webhooks. Not handler_api compatible (mapping below). |
| Payment | Crypto deposits. |
| Price | Per service, shown before you order. See pricing. |
Two honest differences. First, we are US numbers only, the same as DaisySMS was. If you need other countries, look elsewhere. Second, our API is not a drop-in handler_api.php clone, so an integration needs a small adapter. The rest of this page is that adapter.
Moving a DaisySMS API integration
Every SMS Portal endpoint takes Authorization: Bearer <token> (create one in the panel under API access) and returns JSON:
{ "data": { }, "success": true, "summery": "…" }Check success, not the HTTP status alone. (summery is spelt that way on purpose; it is the field name.)
There are two one-time servers. Temp (s1) lives under /api/v2/tn101/; Temp (s2) lives under /api/v2/tn102/ and adds the carrier, area-code and specific-number options DaisySMS users will look for.
Call-by-call mapping
DaisySMS (handler_api.php) | SMS Portal |
|---|---|
action=getBalance → ACCESS_BALANCE:50.30 | GET /api/v2/account-details → data.balance |
action=getNumber&service=… → ACCESS_NUMBER:<id>:<number> | POST /api/v2/tn101/request-number with {"service_key": "…"} → data.order_id, data.number |
getNumber … &carriers=att | POST /api/v2/tn102/request-number with "carrier": "at&t" or "tmobile". Add "keep_carrier": true to fail instead of falling back to another carrier. |
getNumber … &areas=212,305 | Same endpoint with "area_codes": "212,305". Add "lock_area_code": true to make it strict. Stock: GET /api/v2/tn102/get-area-stock?service_key=… |
getNumber … &number=… | POST /api/v2/tn102/request-specific-number with number and service_key |
getNumber … &max_price=… | No equivalent. Prices are fixed per service and listed by get-services, so check before you order. |
action=getStatus&id=… → STATUS_WAIT_CODE | GET …/get-number-details?order_id=…. The code field is null while waiting. |
→ STATUS_OK:<code> | The code field is set: pin on s1, code on s2. The full text is in message. |
setStatus&status=8 → ACCESS_CANCEL | POST …/reject-number with {"order_id": …}. On s2 this works from five minutes after purchase; before that it answers 409 with data.retry_after_seconds. |
setStatus&status=6 (done) | Nothing to call. An order that received its code is complete. |
action=keep | Rent instead: POST /api/v2/rental/request-number. Or POST …/reuse-number to get a past number again. |
| Service list | GET /api/v2/tn101/get-services or /tn102/get-services, which also return prices and surcharges. |
Error strings
| DaisySMS | SMS Portal |
|---|---|
BAD_KEY | HTTP 401, success: false |
NO_MONEY | HTTP 400, success: false, with the reason in summery |
NO_NUMBERS | HTTP 400, success: false. On s2, check get-area-stock first, or relax lock_area_code. |
MAX_PRICE_EXCEEDED | Not applicable: no bidding |
NO_ACTIVATION | HTTP 404 on get-number-details |
| Validation problems | HTTP 422, field errors keyed by name in data |
A drop-in adapter
If your code is full of getNumber and getStatus calls, the least disruptive migration is a small shim with the same shape. In Python:
import os
import requests
BASE = "https://smsportal.io/api/v2"
HEADERS = {"Authorization": f"Bearer {os.environ['SMSPORTAL_TOKEN']}"}
class SmsPortalError(Exception):
pass
def _call(method, path, **kwargs):
body = requests.request(method, f"{BASE}{path}", headers=HEADERS, timeout=30, **kwargs).json()
if not body.get("success"):
raise SmsPortalError(body.get("summery") or "request failed")
return body["data"]
def get_balance():
return _call("GET", "/account-details")["balance"]
def get_number(service, carrier=None, areas=None):
"""Like DaisySMS getNumber. Returns (order, number)."""
if carrier or areas:
payload = {"service_key": service}
if carrier:
payload["carrier"] = {"att": "at&t", "tmo": "tmobile"}[carrier]
if areas:
payload["area_codes"] = ",".join(areas)
data = _call("POST", "/tn102/request-number", json=payload)
return ("s2", data["order_id"]), data.get("number")
data = _call("POST", "/tn101/request-number", json={"service_key": service})
return ("s1", data["order_id"]), data.get("number")
def get_status(order):
"""Like DaisySMS getStatus. Returns 'STATUS_WAIT_CODE' or 'STATUS_OK:<code>'."""
server, order_id = order
path = "/tn101/get-number-details" if server == "s1" else "/tn102/get-number-details"
data = _call("GET", path, params={"order_id": order_id})
code = data.get("pin") if server == "s1" else data.get("code")
return f"STATUS_OK:{code}" if code else "STATUS_WAIT_CODE"
def cancel(order):
"""Like DaisySMS setStatus=8."""
server, order_id = order
path = "/tn101/reject-number" if server == "s1" else "/tn102/reject-number"
_call("POST", path, json={"order_id": order_id})Two things to adjust for. service_key values are not the same short codes DaisySMS used, so pull get-services once and build a lookup table from your old codes to ours. And if number comes back empty, read it from get-number-details on the next poll.
Replace polling with webhooks
DaisySMS asked you to poll getStatus no faster than every three seconds. You can keep polling, but it is simpler to register a webhook endpoint in the panel and subscribe to sms.received. Deliveries are signed with HMAC-SHA256 (X-Webhook-Signature, X-Webhook-Timestamp) and retried on failure. The SMS verification testing guide has a verification snippet.
Migration checklist
- Create an account and make a small deposit.
- Order one number by hand in the panel for the service you use most, and confirm the code arrives.
- Create an API token under API access.
- Map your old service codes to our
service_keyvalues fromget-services. - Swap in the adapter above, or port your calls using the mapping table.
- Add a webhook for
sms.receivedif you want to stop polling. - Run a handful of real orders before moving your full volume.
Other options
To be fair about it: other services still operating include TextVerified (also US-focused, and also says it uses real carrier numbers), SMSPool and 5SIM (many countries; check each one's number type for your platform). We compared the main ones in best SMS verification services. Price the exact service you need on two or three before depositing anywhere.
FAQ
Is DaisySMS still working?
No. Its site says it shut down on March 26, 2026. Sign-ups and deposits were disabled from February 24, 2026.
Can I get my DaisySMS balance back?
The shutdown notice lists only a support address and does not describe balance refunds. Contact DaisySMS directly; we have no access to DaisySMS accounts.
Is there a DaisySMS-compatible API?
Not here. Our API is REST and JSON rather than handler_api.php. The mapping and adapter above cover every call DaisySMS documented, and most integrations port in an afternoon.
Does SMS Portal offer Verizon numbers?
No. Carrier selection covers AT&T and T-Mobile. Without a carrier filter, orders draw from the whole pool of US mobile numbers.