Authentication
All authenticated endpoints require a Bearer token in the Authorization header.
HTTPAuthorization: Bearer tah_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Admin endpoints use the API_ADMIN_SECRET value from your .env file:
HTTPAuthorization: Bearer YOUR_ADMIN_SECRET_HERE
API keys can be created via POST /api/v1/api-keys or by the admin at POST /api/v1/admin/users/{id}/api-key.
Error Format
All errors return JSON with ok: false:
JSON{
"ok": false,
"error": "INSUFFICIENT_BALANCE",
"message": "Insufficient balance. Required: $3.5000 · Available: $1.2000"
}
| Error Code | HTTP | Meaning |
|---|---|---|
UNAUTHORIZED |
401 | Missing or invalid Bearer token |
INVALID_API_KEY |
401 | Key not found or wrong |
KEY_REVOKED |
401 | Key has been revoked |
ACCOUNT_SUSPENDED |
403 | User is banned |
INSUFFICIENT_SCOPE |
403 | Key lacks required scope |
FORBIDDEN |
403 | Admin only |
NOT_FOUND |
404 | Resource not found |
OUT_OF_STOCK |
404 | No stock available |
INSUFFICIENT_BALANCE |
402 | Not enough wallet balance |
CONFLICT |
409 | Race condition — retry |
RATE_LIMITED |
429 | Too many requests |
SERVER_ERROR |
500 | Internal error |
BAD_REQUEST |
400 | Invalid input |
Rate Limits
- Default: 60 requests per minute per API key
- Controlled by
API_RATE_LIMITenv var - On limit hit: HTTP 429 +
Retry-Afterheader
Profile & Wallet
GET /api/v1/me
Returns your full profile, balance, referral info, and endpoint map.
BASHcurl https://yourdomain.com/api/v1/me \
-H "Authorization: Bearer tah_live_xxx"
Response:
JSON{
"ok": true,
"user": {
"id": 123456789,
"telegram_id": 123456789,
"name": "Aditya",
"username": "@aditya",
"balance_usd": 12.3400,
"balance_display": "$12.34",
"total_spent_usd": 45.00,
"referral_code": "a1b2c3d4",
"referral_url": "https://t.me/YourBot?start=ref_a1b2c3d4",
"referral_count": 5,
"referral_earned": 2.50,
"lang": "en",
"joined_at": 1751234567
},
"api": {
"version": "1.0.0",
"endpoints": { ... }
}
}
GET /api/v1/wallet/balance
Scope: read
JSON{
"ok": true,
"balance_usd": 12.34,
"balance_display": "$12.34",
"total_spent_usd": 45.00
}
GET /api/v1/wallet/transactions
Scope: read
Query params: page (default 0), limit (default 20, max 50)
JSON{
"ok": true,
"transactions": [
{
"id": 1,
"user_id": 123456789,
"event_type": "debit",
"amount_usd": 3.50,
"source": "api_checkout",
"created_at": 1751234567
}
],
"total": 10,
"page": 0,
"limit": 20
}
API Key Management
GET /api/v1/api-keys
List all your API keys (keys are masked — only prefix shown).
JSON{
"ok": true,
"api_keys": [
{
"id": 1,
"name": "My App",
"key_prefix": "tah_live_abc12···",
"scopes": "read,orders,download",
"last_used_at": 1751234567,
"revoked_at": null,
"created_at": 1751000000
}
]
}
POST /api/v1/api-keys
Create a new API key. The full key is shown only once.
Scope: api_keys
Request:
JSON{
"name": "Production App",
"scopes": "read,orders,download"
}
Available scopes: read, orders, download, api_keys
Response:
JSON{
"ok": true,
"api_key": "tah_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"prefix": "tah_live_abc12···",
"name": "Production App",
"scopes": "read,orders,download",
"warning": "Store this key securely. It will NOT be shown again."
}
DELETE /api/v1/api-keys/{id}
Revoke an API key immediately.
JSON{ "ok": true, "message": "API key revoked successfully." }
POST /api/v1/api-keys/{id}/rotate
Regenerate a key. Old key becomes invalid immediately.
Scope: api_keys
JSON{
"ok": true,
"api_key": "tah_live_new_key_here...",
"prefix": "tah_live_new···",
"warning": "Your old key is now invalid. Update all integrations immediately."
}
Catalog — Number Services
GET /api/v1/catalog/services
Public endpoint — no auth required.
Returns all available phone number subcategories grouped by category.
JSON{
"ok": true,
"services": [
{
"service_id": 3,
"slug": "number_3",
"name": "India Premium",
"type": "number",
"category_id": 1,
"category_name": "Virtual Numbers",
"stock": 120,
"min_price_usd": 0.50,
"max_price_usd": 0.50
}
],
"categories": [
{ "category_id": 1, "category_name": "Virtual Numbers", "total_stock": 120 }
]
}
GET /api/v1/catalog/services/{slug}/prices
Public endpoint — no auth required.
Slug format: number_{subcategory_id} (from catalog above)
JSON{
"ok": true,
"slug": "number_3",
"name": "India Premium",
"prices": [
{ "country": "IN", "price_usd": 0.5, "stock": 120 }
],
"total_stock": 120
}
Number Orders
POST /api/v1/checkout
Buy a phone number using your wallet balance.
Scope: orders
Request:
JSON{
"service": "number_3"
}
Idempotency: Add X-Idempotency-Key: <unique_uuid> header to prevent duplicate orders.
Response:
JSON{
"ok": true,
"order": {
"id": 42,
"order_number": "TAH-MNO12-ABC123",
"type": "number",
"status": "completed",
"phone": "+919876543210",
"sms_code": null,
"price_charged_usd": 0.50,
"price_display": "$0.50",
"item_count": 1,
"download_ready": false,
"created_at": 1751234567,
"completed_at": 1751234567,
"cancelled_at": null,
"download_count": 0
}
}
GET /api/v1/orders
List your number orders.
Scope: read
Query params: page, limit, status
GET /api/v1/orders/{id}
Get one number order.
GET /api/v1/orders/{id}/code
Poll for the SMS/OTP code for a number order.
The bot will fetch the code from the account's Telegram session and fulfill it. Poll every 5–10 seconds.
Response when pending:
JSON{
"ok": true,
"code": null,
"status": "pending",
"phone": "+919876543210",
"message": "Code is being fetched. Poll this endpoint again in 5–10 seconds."
}
Response when fulfilled:
JSON{
"ok": true,
"code": "12345",
"status": "fulfilled",
"phone": "+919876543210"
}
POST /api/v1/orders/{id}/cancel
Cancel an order in processing or pending_sms status. Balance is automatically refunded.
Scope: orders
JSON{
"ok": true,
"message": "Order cancelled. Refund applied.",
"refunded_usd": 0.50
}
Catalog — Digital Products
These are session file products (sold as encrypted archives).
GET /api/v1/catalog/digital/categories
Public — no auth required.
JSON{
"ok": true,
"categories": [
{ "category_id": 2, "category_name": "Session Files", "total_stock": 48 }
]
}
GET /api/v1/catalog/digital/categories/{id}/products
Public — no auth required.
JSON{
"ok": true,
"category_id": 2,
"category_name": "Session Files",
"products": [
{
"product_id": 7,
"product_name": "India Session 6M+",
"total_stock": 20,
"retail_price_usd": 3.50,
"max_price_usd": 4.00,
"wallet_price": "$3.50"
}
]
}
Digital Orders
POST /api/v1/digital/checkout
Purchase session files. Deducts from wallet. Returns a time-limited download URL.
Scope: orders
Request:
JSON{
"product_id": 7,
"quantity": 3
}
Response:
JSON{
"ok": true,
"order": {
"id": 55,
"order_number": "TAH-XYZ-123ABC",
"type": "digital",
"status": "completed",
"price_charged_usd": 10.50,
"item_count": 3,
"download_ready": true,
"created_at": 1751234567
},
"download_url": "https://yourdomain.com/api/v1/digital/orders/55/download?token=abc123...",
"download_expires_in": "300s",
"download_expires_at": 1751234867,
"note": "Download URL expires in 300 seconds. Request a fresh URL anytime from GET /api/v1/digital/orders/{id}/link"
}
GET /api/v1/digital/orders
List your digital orders. Scope: read
GET /api/v1/digital/orders/{id}
Get one digital order.
GET /api/v1/digital/orders/{id}/link
Get a fresh download URL (5-minute window) for a completed order.
Scope: download
JSON{
"ok": true,
"order_id": 55,
"download_url": "https://yourdomain.com/api/v1/digital/orders/55/download?token=def456...",
"download_expires_in": "300s",
"download_expires_at": 1751235167,
"download_count": 2
}
GET /api/v1/digital/orders/{id}/download?token={token}
Download the session ZIP archive.
Scope: download
Returns binary application/zip containing .session files named by phone number.
BASHcurl "https://yourdomain.com/api/v1/digital/orders/55/download?token=abc123" \
-H "Authorization: Bearer tah_live_xxx" \
-o sessions_TAH-XYZ-123ABC.zip
⚠️ Token expires in 300 seconds. If expired, call
/linkto get a fresh one.
Referral Program
GET /api/v1/referral
Get your referral code, URL, earnings, and current program rules.
JSON{
"ok": true,
"referral_code": "a1b2c3d4",
"referral_url": "https://t.me/YourBot?start=ref_a1b2c3d4",
"referrals_count": 5,
"total_earned_usd": 2.50,
"program": {
"enabled": true,
"trigger": "purchase",
"reward_type": "percent",
"reward_value": 5.0,
"reward_label": "5% of purchase",
"min_purchase": 0.0,
"once_per_user": true,
"max_uses": 0
}
}
GET /api/v1/referral/stats
View your referral event history (last 100 events).
JSON{
"ok": true,
"events": [
{
"id": 1,
"trigger_type": "purchase",
"purchase_amount": 10.00,
"reward_usd": 0.50,
"created_at": 1751234567,
"first_name": "Bob",
"username": "bob_user"
}
],
"total_earned_usd": 0.50
}
Admin Endpoints
All admin endpoints require Authorization: Bearer <API_ADMIN_SECRET>.
GET /api/v1/admin/referral-settings
View current referral configuration.
POST /api/v1/admin/referral-settings
Update referral program settings. All fields are optional.
JSON{
"enabled": 1,
"trigger_on": "purchase",
"reward_type": "percent",
"reward_value": 5.0,
"min_purchase": 1.00,
"once_per_refer": 1,
"max_uses": 0
}
| Field | Type | Values | Description |
|---|---|---|---|
enabled |
int | 1/0 |
Enable/disable program |
trigger_on |
str | signup, purchase, both |
When to give reward |
reward_type |
str | percent, fixed |
Reward calculation method |
reward_value |
float | e.g. 5.0 |
% or USD amount |
min_purchase |
float | e.g. 1.00 |
Min purchase to trigger |
once_per_refer |
int | 1/0 |
Referrer earns once per referred user |
max_uses |
int | 0 = unlimited |
Max total rewards per referrer |
POST /api/v1/admin/users/{telegram_id}/balance
Adjust a user's wallet balance.
JSON{
"amount": 5.00,
"direction": "add"
}
direction: "add" or "deduct"
JSON{
"ok": true,
"user_id": 123456789,
"adjustment_usd": 5.00,
"new_balance_usd": 17.34,
"message": "Balance updated."
}
POST /api/v1/admin/users/{telegram_id}/api-key
Create an API key on behalf of a user (they can use this to access the API).
JSON{
"name": "User's App",
"scopes": "read,orders,download,api_keys"
}
JSON{
"ok": true,
"api_key": "tah_live_xxxxxxxx...",
"prefix": "tah_live_abc12···",
"for_user_id": 123456789,
"scopes": "read,orders,download,api_keys",
"warning": "Store this key securely. It will NOT be shown again."
}
GET /api/v1/admin/code-requests
Poll for pending OTP code requests. Your bot should call this endpoint regularly and fulfill codes.
JSON{
"ok": true,
"pending_code_requests": [
{
"id": 3,
"api_order_id": 42,
"status": "pending",
"requested_at": 1751234567,
"phone": "+919876543210",
"user_id": 123456789
}
]
}
POST /api/v1/admin/orders/{id}/fulfill-code
Post the OTP code for a pending code request.
JSON{ "code": "12345" }
JSON{
"ok": true,
"message": "Code fulfilled.",
"order_id": 42,
"code": "12345"
}
Status Codes
Number Orders
| Status | Meaning |
|---|---|
processing |
Order created, not yet delivered |
pending_sms |
Awaiting OTP code |
completed |
Phone delivered |
cancelled |
Cancelled, balance refunded |
failed |
Failed delivery |
Digital Orders
| Status | Meaning |
|---|---|
processing |
Order created |
completed |
Sessions ready to download |
failed |
Delivery failed |
refunded |
Refunded by admin |
Referral System Rules
CODEHow it works:
1. User shares their referral URL (https://t.me/YourBot?start=ref_CODE)
2. New user starts the bot with that link → bot stores referral relationship
3. When referred user triggers the configured event → referrer earns reward
Trigger options:
signup → Referrer earns when referred user first starts the bot
purchase → Referrer earns when referred user completes a purchase
both → Referrer earns on both events
Reward types:
percent → Referrer earns X% of each qualifying purchase
fixed → Referrer earns a flat $X per qualifying event
once_per_refer = 1:
Referrer earns at most once per referred user (per trigger type)
E.g. if trigger=purchase, referrer earns only on the FIRST purchase
max_uses = 0 → unlimited total referrals
max_uses = N → referrer can only earn from N total referred users
min_purchase → purchase must be at least $X to qualify for percent reward
Idempotency
To prevent duplicate orders on retries, include:
HTTPX-Idempotency-Key: <unique-uuid-per-request>
If a request with the same key already succeeded, the same order is returned with "idempotent": true.
Setup Guide
1. Add to .env
ENVAPI_ADMIN_SECRET=your_strong_admin_secret_here_change_this
BOT_USERNAME=YourBotUsername
API_RATE_LIMIT=60
FERNET_KEY=your_existing_fernet_key_from_bot_env
2. Place api.php and .htaccess in your web root
Same directory as your bot (where data/store.db lives).
3. Enable PHP extensions
Required: pdo_sqlite, openssl, zip
4. Test the API
BASH# Health check
curl https://yourdomain.com/api/v1
# Create your first API key (as admin)
curl -X POST https://yourdomain.com/api/v1/admin/users/YOUR_TELEGRAM_ID/api-key \
-H "Authorization: Bearer YOUR_ADMIN_SECRET" \
-H "Content-Type: application/json" \
-d '{"name":"My App","scopes":"read,orders,download,api_keys"}'
# Browse catalog
curl https://yourdomain.com/api/v1/catalog/services
# Buy a number
curl -X POST https://yourdomain.com/api/v1/checkout \
-H "Authorization: Bearer tah_live_xxx" \
-H "Content-Type: application/json" \
-H "X-Idempotency-Key: $(uuidgen)" \
-d '{"service":"number_1"}'
5. Bot integration for OTP codes
Have your bot poll GET /api/v1/admin/code-requests every 30 seconds, fetch the OTP from the session, then call POST /api/v1/admin/orders/{id}/fulfill-code with the code.
TeleAccountHub API v1.0.0 — Powered by the Telegram Bot's SQLite database