DaisySim API
Programmatic access to US virtual phone numbers for SMS verification. Purchase numbers, poll for OTP codes, and manage activations โ all via a simple REST interface with wallet-based billing.
Endpoint Reference
Authentication
Bearer Token Required
Every request must include your API key as a Bearer token in the Authorization header. Keys are issued per account from your API Keys page and tied to your wallet balance.
Authorization: Bearer YOUR_API_KEY
curl -X GET \ https://daisysim.com/api/v1/server7/balance \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Accept: application/json"
Rate Limits
Rate limits are enforced per account per minute. Exceeding a limit returns HTTP
| Endpoint | Limit | Window |
|---|---|---|
| POST /purchase | 10 requests | per 60 seconds |
| GET /check/{id} | 60 requests | per 60 seconds |
| POST /cancel/{id} | 10 requests | per 60 seconds |
"Too many purchase attempts. Please wait 43s."
Error Codes
All responses share a consistent envelope. On error,
| HTTP | code | Description |
|---|---|---|
| 401 | UNAUTHENTICATED | Missing or invalid API key |
| 403 | ACCOUNT_SUSPENDED | Account has been blocked |
| 403 | ACCOUNT_LOCKED | Account is temporarily locked |
| 404 | NOT_FOUND | Activation ID not found or does not belong to your account |
| 409 | CONCURRENT_ERROR | Concurrent transaction detected โ retry immediately |
| 422 | PRICE_VERIFICATION_FAILED | Service price could not be verified โ re-fetch |
| 422 | CODE_RECEIVED | Cannot cancel โ SMS code already arrived. The |
| 422 | TOO_EARLY | Must wait 3 minutes from purchase before cancelling. Error message includes exact second(s) remaining. |
| 422 | INVALID_COUNTRY | Country not supported โ use |
| 400 | INSUFFICIENT_BALANCE | Wallet balance too low for this purchase |
| 429 | RATE_LIMITED | Too many requests โ wait the number of seconds in the error message before retrying |
| 503 | OUT_OF_STOCK | No numbers available from the selected pool right now โ try again shortly, or omit |
| 502 | PROVIDER_ERROR | Upstream error โ retry in a few seconds |
| 500 | SERVER_ERROR | Internal server error |
{
"success": false,
"error": "Human-readable error message",
"code": "MACHINE_READABLE_CODE"
}
Balance
Returns your current wallet balance in USD along with your account email.
Response Fields
| balance | float | Current wallet balance in USD (4 decimal places) |
| currency | string | Always |
| string | Authenticated account email |
{
"success": true,
"message": "OK",
"data": {
"balance": 14.2500,
"currency": "USD",
"email": "[email protected]"
}
}
Countries
Returns the list of supported countries. Currently USA only. Use the returned
{
"success": true,
"message": "OK",
"data": {
"countries": [
{ "id": "USA", "name": "USA" }
]
}
}
Apps
Returns all available services for a country with your final wallet price. Services prefixed
PRICE_VERIFICATION_FAILED โ re-fetch /apps and retry.
provider_id is supplied, that exact pool is used โ if it has no stock the purchase is rejected with OUT_OF_STOCK, no fallback occurs. Omit provider_id to use the cheapest available pool.
Path Parameters
| Param | Type | Required | Description |
|---|---|---|---|
| country | string | required | Country ID from |
Response Fields (per service)
| code | string | Service identifier โ pass as |
| name | string | Human-readable service name |
| price | float | Price charged to your wallet in USD (4 decimal places). For multi-pool |
| providers | array | Always present. Empty array |
Provider Object Fields (sb_* services only)
| provider_id | string | Opaque pool identifier โ pass to |
| price | float | Price for this specific pool including platform markup |
| count | integer | Approximate number of available numbers from this pool right now |
{
"success": true,
"message": "OK",
"data": [
// โโ Single-provider services โ providers is always an empty array โโ
{
"code": "WhatsApp",
"name": "WhatsApp",
"price": 1.8500,
"providers": []
},
{
"code": "whatsapp-(us)5",
"name": "WhatsApp 2",
"price": 0.7400,
"providers": []
},
{
"code": "Signal",
"name": "Signal",
"price": 0.6000,
"providers": []
},
{
"code": "Telegram",
"name": "Telegram",
"price": 1.4000,
"providers": []
},
// โโ Multi-pool services โ providers array is non-empty, sorted cheapest-first โโ
{
"code": "sb_wa",
"name": "WhatsApp 3",
"price": 1.0830,
"providers": [
{ "provider_id": "3109", "price": 1.0830, "count": 4000 },
{ "provider_id": "2266", "price": 1.0920, "count": 4296 },
{ "provider_id": "3170", "price": 1.3810, "count": 1000 },
{ "provider_id": "2617", "price": 3.6000, "count": 344 }
]
},
{
"code": "sb_tg",
"name": "Telegram 2",
"price": 0.4500,
"providers": [
{ "provider_id": "2266", "price": 0.4500, "count": 1820 },
{ "provider_id": "3109", "price": 0.6000, "count": 980 }
]
},
{
"code": "sb_fb",
"name": "Facebook",
"price": 0.5000,
"providers": [
{ "provider_id": "3109", "price": 0.5000, "count": 2100 },
{ "provider_id": "2266", "price": 0.6500, "count": 890 }
]
}
]
}
Purchase
Purchase a US virtual number for a specific service. Your wallet is debited by the actual price of the assigned number. Returns the phone number and activation ID needed to poll for your SMS code. Rate limited to 10 requests per 60 seconds.
app and optional provider_id you supply. If the service is no longer available, the purchase is rejected with PRICE_VERIFICATION_FAILED โ re-fetch /apps and retry.
OUT_OF_STOCK. No fallback to other pools occurs. Omit provider_id to use the cheapest available pool. For non-sb_* services (WhatsApp, WhatsApp 2, Signal, Telegram and its variants) provider_id is ignored entirely.
Request Body application/json
| Field | Type | Required | Description |
|---|---|---|---|
| country | string | required | Country ID โ e.g. |
| app | string | required | Service |
| provider_id | string | optional | Pool to use โ taken from |
| app_name | string | optional | Human-readable label stored on the order (defaults to |
| country_name | string | optional | Human-readable country label stored on the order (defaults to |
cURL Examples
curl -X POST \ https://daisysim.com/api/v1/server7/purchase \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "country": "USA", "app": "WhatsApp" }'
curl -X POST \ https://daisysim.com/api/v1/server7/purchase \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "country": "USA", "app": "sb_wa" }'
curl -X POST \ https://daisysim.com/api/v1/server7/purchase \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "country": "USA", "app": "sb_wa", "provider_id": "3109" }'
Response Fields
| activation_id | string | Unique ID โ use for |
| phone_number | string | The virtual US number to use for verification |
| service | string | Service name as stored on the order |
| country | string | Country label |
| amount_charged | float | Exact amount deducted from your wallet in USD. Always matches the price of the pool used. |
| balance_after | float | Wallet balance after this purchase |
{
"success": true,
"message": "Number purchased successfully.",
"data": {
"activation_id": "32886",
"phone_number": "+19401234567",
"service": "WhatsApp 3",
"country": "USA",
"amount_charged": 1.0830,
"balance_after": 12.4000
}
}
{
"success": false,
"error": "Insufficient wallet balance.",
"code": "INSUFFICIENT_BALANCE"
}
{
"success": false,
"error": "No numbers available right now. Please try again shortly.",
"code": "OUT_OF_STOCK"
}
Check SMS
Poll for an incoming SMS code on a purchased number. The server caches
Waiting responses. Polling faster offers no advantage. As soon as a code arrives it bypasses the cache and is returned immediately on the next call.
Path Parameters
| Param | Type | Required | Description |
|---|---|---|---|
| activation_id | string | required | The |
Status Values
| Waiting | Number active, no SMS received yet โ poll again in 15 seconds |
| Completed | Code received โ present in the |
{
"success": true,
"message": "OK",
"data": {
"activation_id": "32886",
"status": "Waiting",
"code": null,
"phone_number": "+19401234567"
}
}
{
"success": true,
"message": "OK",
"data": {
"activation_id": "32886",
"status": "Completed",
"code": "847261",
"phone_number": "+19401234567"
}
}
Check All
Batch poll up to 20 activations in a single request. Useful when managing multiple concurrent numbers. The same 15-second server-side cache applies per activation ID.
Request Body application/json
| Field | Type | Required | Description |
|---|---|---|---|
| ids | array | required | Array of |
Per-Item Response Fields
| activation_id | string | The queried activation ID |
| status | string | |
| code | string|null | OTP code โ only present when |
| phone_number | string|null | The virtual number โ present when |
Not Found or Invalid will never change โ remove them from your polling set immediately. Keep re-submitting only Waiting IDs every 15 seconds.
{
"success": true,
"message": "OK",
"data": [
{
"activation_id": "32886",
"status": "Completed",
"code": "847261",
"phone_number": "+19401234567"
},
{
"activation_id": "32887",
"status": "Waiting",
"code": null,
"phone_number": "+19402345678"
},
{
// phone_number is not included for Not Found / Invalid items
"activation_id": "99999",
"status": "Not Found",
"code": null
}
]
}
Cancel
Cancel an active number and receive a full refund to your wallet. Only allowed after 3 minutes (180 seconds) from purchase and only if no SMS code has been received. Numbers whose time window has already expired are also fully refunded โ no need to check status before calling cancel. Rate limited to 10 requests per 60 seconds.
TOO_EARLY. The error message includes the exact number of second(s) remaining โ e.g. "Cancellation not yet allowed. Please wait 94 more second(s)." โ use this value to drive a countdown timer.
CODE_RECEIVED (HTTP 422) and includes the code in the data object โ treat this exactly like a successful check response.
Path Parameters
| Param | Type | Required | Description |
|---|---|---|---|
| activation_id | string | required | The activation to cancel |
Response Fields (on success)
| activation_id | string | The cancelled activation ID |
| refund | float | Amount refunded to your wallet in USD |
| balance_after | float | Wallet balance after the refund |
{
"success": true,
"message": "Activation cancelled and refunded.",
"data": {
"activation_id": "32886",
"refund": 1.0830,
"balance_after": 14.2500
}
}
{
"success": false,
"error": "Cancellation not yet allowed. Please wait 94 more second(s).",
"code": "TOO_EARLY"
}
{
"success": false,
"error": "Code already received. Cannot cancel.",
"code": "CODE_RECEIVED",
"data": {
"activation_id": "32886",
"phone_number": "+19401234567",
"service": "WhatsApp 3",
"status": "Completed",
"code": "847261"
}
}
History
Returns a paginated list of your activation orders, newest first. Filter by status using the optional query parameter.
Query Parameters
| Param | Type | Required | Description |
|---|---|---|---|
| status | string | optional | Filter: |
| per_page | integer | optional | Results per page โ default |
Order Object Fields
| activation_id | string | Unique activation identifier |
| phone_number | string | The virtual US number that was assigned |
| service | string | Service name (e.g. WhatsApp 3) |
| country | string | Country label |
| status | string | |
| code | string|null | Received OTP code โ |
| amount_charged | float | Amount deducted from wallet in USD |
| created_at | string | ISO 8601 purchase timestamp |
| completed_at | string|null | ISO 8601 timestamp when code was first received. |
{
"success": true,
"message": "OK",
"data": {
"orders": [
{
"activation_id": "32886",
"phone_number": "+19401234567",
"service": "WhatsApp 3",
"country": "USA",
"status": "Completed",
"code": "847261",
"amount_charged": 1.0830,
"created_at": "2025-03-31T02:20:00+00:00",
"completed_at": "2025-03-31T02:21:44+00:00"
},
{
"activation_id": "32880",
"phone_number": "+19403456789",
"service": "Signal",
"country": "USA",
"status": "Cancelled",
"code": null,
"amount_charged": 0.6000,
"created_at": "2025-03-31T01:10:00+00:00",
"completed_at": null
}
],
"pagination": {
"current_page": 1,
"per_page": 20,
"total": 335,
"last_page": 17
}
}
}
Complete Integration Example
A full purchase-to-code flow in JavaScript โ pool selection, 15-second polling via check-all, and cancellation with race-condition handling.
const API = "https://daisysim.com/api/v1/server7"; const KEY = "YOUR_API_KEY"; const heads = { "Authorization": `Bearer ${KEY}`, "Content-Type": "application/json" }; // 1. Fetch available services (per-account cache: 5 min) const appsRes = await fetch(`${API}/apps/USA`, { headers: heads }); const apps = (await appsRes.json()).data; // 2. Pick a service โ sb_wa has multiple pools const svc = apps.find(a => a.code === "sb_wa"); // 3a. Option A โ auto-select cheapest pool (omit provider_id) const bodyAuto = { country: "USA", app: svc.code }; // 3b. Option B โ pin to a specific pool; purchase fails if that pool has no stock const cheapest = svc.providers[0]; // already sorted cheapest-first const bodyPinned = { country: "USA", app: svc.code, provider_id: cheapest.provider_id }; // 4. Purchase (rate limit: 10/min) const buy = await fetch(`${API}/purchase`, { method: "POST", headers: heads, body: JSON.stringify(bodyPinned) }).then(r => r.json()); if (!buy.success) { if (buy.code === "OUT_OF_STOCK") { // The pinned pool had no stock โ re-fetch /apps and pick a different provider_id // Or omit provider_id entirely to use the cheapest available pool } if (buy.code === "RATE_LIMITED") { // buy.error includes wait time โ parse and schedule retry } throw new Error(buy.error); } // amount_charged always matches the price of the pool used const { activation_id, phone_number, amount_charged } = buy.data; console.log(`Number: ${phone_number} | Charged: $${amount_charged}`); // 5. Poll every 15 seconds (matches server cache TTL โ faster polling wastes requests) let code = null; const POLL_INTERVAL = 15000; // 15 s const MAX_POLLS = 40; // ~10 minutes max for (let i = 0; i < MAX_POLLS; i++) { await new Promise(r => setTimeout(r, POLL_INTERVAL)); const poll = await fetch(`${API}/check-all`, { method: "POST", headers: heads, body: JSON.stringify({ ids: [activation_id] }) }).then(r => r.json()); const item = poll.data.find(r => r.activation_id === activation_id); // Drop unresolvable IDs immediately โ they will never change if (["Not Found", "Invalid"].includes(item?.status)) break; if (item?.status === "Completed") { code = item.code; break; } } // 6. Cancel & refund if no code (only allowed after 3-min lock) if (!code) { const cancel = await fetch(`${API}/cancel/${activation_id}`, { method: "POST", headers: heads }).then(r => r.json()); if (cancel.success) { console.log(`Refunded $${cancel.data.refund}`); } else if (cancel.code === "TOO_EARLY") { // e.g. "Please wait 94 more second(s)." โ parse and retry after that delay console.log(cancel.error); } else if (cancel.code === "CODE_RECEIVED") { // Code arrived in the race window โ data.code has it code = cancel.data.code; } } if (code) console.log(`OTP: ${code}`);