# Ada OTP API (v1.1.0)

> REST API for virtual phone numbers (SMS OTP), social media services (SMM), Gmail accounts, email rental and ready-made WhatsApp numbers. All products share one balance.

- Base URL: https://api.adaotp.com/api/v1
- OpenAPI 3.0 spec: https://api.adaotp.com/openapi.json
- HTML docs: https://api.adaotp.com/api-docs

## Authentication

Every request needs your API key. Find it in Dashboard → Profile → API. Send it as the `X-API-Key` header (recommended), `Authorization: Bearer <key>`, or the `apikey` query parameter. Keep the key secret; if it leaks, contact support and we will rotate it.

## Conventions

- Base URL: `https://api.adaotp.com/api/v1`. Request bodies may be JSON (`Content-Type: application/json`) or form-encoded; file uploads use `multipart/form-data`.
- Every response is JSON with `success` (boolean), `message` and `data`. Always check `success` before reading `data`.
- Errors also carry a machine-readable `error_code` (see Error codes) and a `request_id`. Branch on `error_code`, not on `message` — message text may change.
- Amounts are integers in Indonesian Rupiah (IDR). Timestamps are ISO 8601 or `Y-m-d H:i:s` in Asia/Jakarta (UTC+7).
- Rate limit: 360 requests per minute per API key. Watch the `X-RateLimit-Remaining` header; HTTP 429 means wait and retry.
- Idempotency: purchase endpoints accept an optional `Idempotency-Key` header (8–128 chars). Retrying with the same key within 24 h returns the first result instead of buying twice — use a fresh UUID per purchase.
- Every response has an `X-Request-Id` header. Include it when contacting support.

## Quick start (virtual number)

1. Check your balance: `GET /balance`
2. Find the service id (e.g. WhatsApp): `GET /services`
3. List countries & prices for that service; pick an entry `id`: `GET /services/{service_id}/countries`
4. Buy a number: `POST /orders`
5. Poll every 5–10 s until `latest_code` is filled: `GET /orders/{order_uuid}`
6. Finish the order when done, or cancel it for a refund if no SMS arrives: `POST /orders/{order_uuid}/finish`

## Account

Balance and profile of the API key owner.

### GET /balance

Get balance. Live balance. Cached for up to 5 seconds.

```bash
curl -X GET 'https://api.adaotp.com/api/v1/balance' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "balance": 305932,
        "balance_formatted": "Rp 305.932",
        "bonus_balance": 0,
        "pending_balance": 0,
        "currency": "IDR"
    },
    "message": "Balance retrieved successfully"
}
```

### GET /profile

Get profile. Account details and active-order stats. The balance here may lag a few seconds behind /balance.

```bash
curl -X GET 'https://api.adaotp.com/api/v1/profile' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "user": {
            "id": 2621,
            "name": "Jane",
            "email": "jane@example.com",
            "balance": "Rp 305.932",
            "created_at": "2026-01-01T00:00:00.000000Z"
        },
        "stats": {
            "total_orders": 1,
            "total_sms": 0,
            "balance_raw": 305932
        }
    },
    "message": "Profile loaded successfully"
}
```

## Virtual numbers (SMS OTP)

Rent a phone number, receive the verification SMS, then finish or cancel. Cancelling before an SMS arrives refunds the full price.

### GET /services

List services. All apps/websites you can receive codes for. Cache this list; it rarely changes.

```bash
curl -X GET 'https://api.adaotp.com/api/v1/services' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": [
        {
            "id": 1276,
            "text": "Whatsapp",
            "description": null,
            "icon": "https://…/svc_ic_1276.webp"
        },
        {
            "id": 718,
            "text": "Google / Youtube / Gmail",
            "description": null,
            "icon": "https://…"
        }
    ],
    "message": "Services retrieved successfully"
}
```

### GET /services/{id}

Get one service

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | integer | yes | Service id from /services |

```bash
curl -X GET 'https://api.adaotp.com/api/v1/services/1276' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "id": 1276,
        "text": "Whatsapp",
        "description": null,
        "icon": "https://…"
    },
    "message": "Service details retrieved successfully"
}
```

### GET /services/{id}/countries

Countries & prices for a service. Each entry is one purchasable offer (country + server + operator). Use the entry `id` as `country` when creating an order. `stock`, `delivery_percent` and `can_order` help you choose; prices change, so read them right before ordering.

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | integer | yes | Service id from /services |

```bash
curl -X GET 'https://api.adaotp.com/api/v1/services/1276/countries' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "status": "success",
        "application_id": 1276,
        "countries": [
            {
                "id": 184809,
                "name": "Indonesia",
                "iso": "ID",
                "prefix": "+62",
                "price": 4720,
                "price_formatted": "Rp 4.720",
                "available": true,
                "provider_id": 3,
                "stock": 110,
                "delivery_percent": 35.8,
                "operator": "any",
                "can_order": true
            }
        ]
    },
    "message": "Service countries retrieved successfully"
}
```

### POST /orders

Buy a number. Charges your balance and reserves a number. Read `order.order_uuid` from the response and poll GET /orders/{order_uuid} for the SMS. With `quantity` > 1 the response also has `orders` and `summary`. The first 3 numbers are created before the response; above 3 the API answers `202` with `background: true` and keeps ordering the rest — poll GET /orders/bulk-status for progress. Ordering stops at the first number that cannot be created (out of stock, balance); you are only charged for numbers created.

Accepts `Idempotency-Key` header.

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `service_id` | body | integer | yes | Service id from /services |
| `country` | body | integer | yes | Offer `id` from /services/{id}/countries (not an ISO code) |
| `quantity` | body | integer | no | How many numbers to buy, 1–30 (default 1) |

```bash
curl -X POST 'https://api.adaotp.com/api/v1/orders' \
  -H 'X-API-Key: YOUR_API_KEY' \
  -H 'Idempotency-Key: 2f6c1b9e-1d0a-4c55-9a4e-6b8f2c7d1e03' \
  -H 'Content-Type: application/json' \
  -d '{"service_id":1276,"country":184809,"quantity":1}'
```

Response (201):

```json
{
    "success": true,
    "data": {
        "results": [
            {
                "success": true,
                "order_uuid": "FBTO1234567890NUM",
                "order": {
                    "…": "raw order object"
                }
            }
        ],
        "summary": {
            "requested": 1,
            "succeeded": 1,
            "failed": 0
        }
    },
    "order": {
        "id": 6751431,
        "order_uuid": "FBTO1234567890NUM",
        "number": "6281234567890",
        "formatted_number": "+62 812-3456-7890",
        "status": "pending",
        "service": {
            "id": 1276,
            "name": "Whatsapp"
        },
        "country": {
            "id": 6,
            "name": "Indonesia",
            "iso_code": "ID",
            "phone_code": "62"
        },
        "price": 4720,
        "currency": "IDR",
        "latest_code": null,
        "sms_count": 0,
        "messages": [],
        "is_expired": false,
        "remaining_time": 1200,
        "created_at": "2026-10-09 08:15:09",
        "expired_at": "2026-10-09 08:35:09"
    },
    "message": "Order created successfully"
}
```

Typical errors: `insufficient_balance`, `out_of_stock`, `rate_limited`, `provider_unavailable`, `validation_error`

### GET /orders/bulk-status

Progress of a multi-number order. Status of your latest order with `quantity` > 3 (kept 30 minutes). `state` is `running` while the rest are being ordered and `done` when finished; `succeeded` counts numbers created so far. `data` is null when there is no recent bulk order. Only one bulk order can run at a time (a second one gets 409).

```bash
curl -X GET 'https://api.adaotp.com/api/v1/orders/bulk-status' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "id": "3f9a1c2b7d10",
        "state": "running",
        "requested": 30,
        "succeeded": 12,
        "failed": 0,
        "message": null,
        "started_at": 1791520000,
        "updated_at": 1791520014
    }
}
```

### GET /orders/{id}

Get one order (poll for the SMS). Recommended polling endpoint. `latest_code` holds the newest code; `messages` lists every SMS newest-first. Poll every 5–10 seconds; responses are cached for 3 seconds. `{id}` is the `order_uuid` (works for any order) or the numeric `id` (active orders only).

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | order_uuid (recommended) or numeric order id |
| `check_sms` | query | boolean | no | true (default) asks the provider for new SMS now; false returns stored data only |

```bash
curl -X GET 'https://api.adaotp.com/api/v1/orders/FBTO1234567890NUM' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "id": 6751431,
        "order_uuid": "FBTO1234567890NUM",
        "number": "6281234567890",
        "formatted_number": "+62 812-3456-7890",
        "status": "completed",
        "service": {
            "id": 1276,
            "name": "Whatsapp"
        },
        "country": {
            "id": 6,
            "name": "Indonesia",
            "iso_code": "ID",
            "phone_code": "62"
        },
        "operator": "any",
        "price": 4720,
        "currency": "IDR",
        "latest_code": "504374",
        "sms_count": 1,
        "messages": [
            {
                "code": "504374",
                "text": "Your WhatsApp code: 504-374",
                "received_at": "2026-10-09T08:16:02+07:00"
            }
        ],
        "can_cancel": false,
        "can_finish": true,
        "is_expired": false,
        "remaining_time": 912,
        "created_at": "2026-10-09 08:15:09",
        "expired_at": "2026-10-09 08:35:09"
    },
    "message": "Order retrieved successfully"
}
```

Typical errors: `order_not_found`

### GET /orders/active

List active orders. All orders still waiting or receiving SMS, plus your order limits. SMS arrays here are oldest-first; prefer GET /orders/{id} when you need the latest code.

```bash
curl -X GET 'https://api.adaotp.com/api/v1/orders/active' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "success": true,
        "orders": [
            {
                "id": 6751431,
                "order_uuid": "FBTO1234567890NUM",
                "number": "6281234567890",
                "status": "pending",
                "sms": [],
                "remaining_time": 1150
            }
        ],
        "count": 1,
        "has_active_orders": true,
        "order_limits": {
            "…": "…"
        }
    },
    "message": "Active orders retrieved successfully"
}
```

### GET /orders/history

Order history (completed)

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `page` | query | integer | no | Page number |
| `per_page` | query | integer | no | Rows per page, 1–50 (default 10) |
| `date_from` | query | string | no | Y-m-d |
| `date_to` | query | string | no | Y-m-d |
| `search` | query | string | no | Number or service name |
| `sort_direction` | query | string | no | asc \| desc (default desc) |

```bash
curl -X GET 'https://api.adaotp.com/api/v1/orders/history' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": [
        {
            "id": 6751431,
            "order_uuid": "FBTO1234567890NUM",
            "number": "6281234567890",
            "status": "completed",
            "price": 4720,
            "sms": [
                {
                    "code": "504374",
                    "text": "…",
                    "timestamp": "2026-10-09T08:16:02+07:00"
                }
            ]
        }
    ],
    "pagination": {
        "current_page": 1,
        "per_page": 10,
        "has_more_pages": false,
        "last_page": 1
    },
    "message": "Completed order history retrieved successfully"
}
```

### POST /orders/{id}/cancel

Cancel an order (refund). Allowed only before an SMS arrives, and usually only after a short minimum wait (`cancel_not_allowed_yet` until then). `DELETE /orders/{id}` does the same.

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | order_uuid or numeric order id |

```bash
curl -X POST 'https://api.adaotp.com/api/v1/orders/FBTO1234567890NUM/cancel' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "message": "Order cancelled successfully",
    "data": null
}
```

Typical errors: `cancel_not_allowed_yet`, `order_already_cancelled`, `order_not_found`

### DELETE /orders/{id}

Cancel an order (alias)

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | order_uuid or numeric order id |

```bash
curl -X DELETE 'https://api.adaotp.com/api/v1/orders/FBTO1234567890NUM' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "message": "Order cancelled successfully",
    "data": null
}
```

### POST /orders/{id}/finish

Finish an order. Mark the order complete after you received the code. Frees your active-order slot.

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes | order_uuid or numeric order id |

```bash
curl -X POST 'https://api.adaotp.com/api/v1/orders/FBTO1234567890NUM/finish' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "message": "Order completed successfully",
    "data": null
}
```

## Social media services (SMM)

Followers, likes, views and more for Instagram, TikTok, YouTube, Facebook, Telegram and other platforms. Delivery is automatic; poll the order for progress.

### GET /smm/platforms

List platforms & service types

```bash
curl -X GET 'https://api.adaotp.com/api/v1/smm/platforms' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "platforms": [
            {
                "key": "instagram",
                "label": "Instagram",
                "total": 870,
                "types": [
                    {
                        "type": "Followers",
                        "total": 197
                    },
                    {
                        "type": "Likes",
                        "total": 198
                    }
                ]
            }
        ]
    },
    "message": "OK"
}
```

### GET /smm/services

List services. Always filter by `platform` + `type`; unfiltered responses are large. `price_per_1000` is in IDR.

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `platform` | query | string | no | Platform key from /smm/platforms |
| `type` | query | string | no | Service type within the platform |
| `category` | query | string | no | Legacy category name (overrides platform/type) |
| `sort` | query | string | no | quality (default) \| price_asc \| price_desc |

```bash
curl -X GET 'https://api.adaotp.com/api/v1/smm/services' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "services": [
            {
                "id": 8112,
                "name": "Instagram Followers Indonesia [Refill 30 days]",
                "platform": "instagram",
                "service_type": "Followers",
                "type": "Default",
                "is_custom": false,
                "price_per_1000": 72000,
                "min": 50,
                "max": 50000,
                "refill": 0,
                "target_label": "Profile link / username",
                "completion_rate": 89,
                "refund_rate": 8,
                "is_recommended": false
            }
        ]
    },
    "message": "OK"
}
```

### GET /smm/services/{id}

Get one service. Current price and min/max — call right before ordering.

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | integer | yes | Service id |

```bash
curl -X GET 'https://api.adaotp.com/api/v1/smm/services/8112' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "id": 8112,
        "name": "…",
        "price_per_1000": 72000,
        "min": 50,
        "max": 50000
    },
    "message": "OK"
}
```

### POST /smm/quote

Calculate price. Preview the price. Does not charge your balance.

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `service_id` | body | integer | yes | Service id |
| `quantity` | body | integer | no | Required for normal services |
| `custom_comments` | body | string | no | Custom-comment services only: one comment per line (quantity = number of lines) |

```bash
curl -X POST 'https://api.adaotp.com/api/v1/smm/quote' \
  -H 'X-API-Key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"service_id":8112,"quantity":1000}'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "quantity": 1000,
        "price": 72000
    },
    "message": "OK"
}
```

### POST /smm/orders

Place an SMM order

Accepts `Idempotency-Key` header.

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `service_id` | body | integer | yes | Service id |
| `target` | body | string | yes | Link or username, as described by the service `target_label` |
| `quantity` | body | integer | no | Between the service min and max |
| `custom_comments` | body | string | no | Custom-comment services only, one per line |

```bash
curl -X POST 'https://api.adaotp.com/api/v1/smm/orders' \
  -H 'X-API-Key: YOUR_API_KEY' \
  -H 'Idempotency-Key: 2f6c1b9e-1d0a-4c55-9a4e-6b8f2c7d1e03' \
  -H 'Content-Type: application/json' \
  -d '{"service_id":8112,"target":"https://instagram.com/username","quantity":1000}'
```

Response (201):

```json
{
    "success": true,
    "data": {
        "order_uuid": "9f1c2f7a-6b41-4a0e-9d2e-1a2b3c4d5e6f",
        "service_id": 8112,
        "target": "https://instagram.com/username",
        "quantity": 1000,
        "price": 72000,
        "status": "pending"
    },
    "message": "Order placed successfully"
}
```

Typical errors: `insufficient_balance`, `validation_error`, `order_failed`

### GET /smm/orders

List SMM orders

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `page` | query | integer | no | Page number |
| `per_page` | query | integer | no | 1–100 (default 25) |
| `status` | query | string | no | pending \| processing \| in_progress \| completed \| partial \| canceled \| failed \| refunded |

```bash
curl -X GET 'https://api.adaotp.com/api/v1/smm/orders' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "orders": [
            {
                "order_uuid": "9f1c2f7a-…",
                "status": "in_progress",
                "start_count": 1520,
                "remains": 400
            }
        ],
        "pagination": {
            "…": "…"
        }
    },
    "message": "OK"
}
```

### GET /smm/orders/{uuid}

Get one SMM order. Refreshed from the provider. `remains` = quantity not yet delivered; `refunded` = IDR returned for undelivered parts.

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `uuid` | path | string | yes | order_uuid |

```bash
curl -X GET 'https://api.adaotp.com/api/v1/smm/orders/9f1c2f7a-6b41-4a0e-9d2e-1a2b3c4d5e6f' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "order_uuid": "9f1c2f7a-…",
        "service_name": "…",
        "target": "…",
        "quantity": 1000,
        "price": 72000,
        "status": "completed",
        "start_count": 1520,
        "remains": 0,
        "refunded": 0,
        "created_at": "2026-10-09T08:00:00+07:00"
    },
    "message": "OK"
}
```

## Gmail accounts

Ready-made Gmail accounts. Credentials are returned immediately and can be read again from your orders. Treat passwords as secrets.

### GET /gmail/stock

Stock & price

```bash
curl -X GET 'https://api.adaotp.com/api/v1/gmail/stock' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "stock": 814,
        "sell_price": 5880,
        "max_qty": 50
    },
    "message": "OK"
}
```

### POST /gmail/orders

Buy Gmail accounts. Charged up front; anything that cannot be delivered is refunded automatically.

Accepts `Idempotency-Key` header.

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `qty` | body | integer | yes | 1–50 (see max_qty) |

```bash
curl -X POST 'https://api.adaotp.com/api/v1/gmail/orders' \
  -H 'X-API-Key: YOUR_API_KEY' \
  -H 'Idempotency-Key: 2f6c1b9e-1d0a-4c55-9a4e-6b8f2c7d1e03' \
  -H 'Content-Type: application/json' \
  -d '{"qty":1}'
```

Response (201):

```json
{
    "success": true,
    "data": {
        "orders": [
            {
                "order_uuid": "c1d2…",
                "email": "someone123@gmail.com",
                "password": "••••••••",
                "price": 5880,
                "status": "completed",
                "refundable": true,
                "deadline_at": "2026-10-10T08:00:00+07:00"
            }
        ]
    },
    "message": "Purchase completed"
}
```

Typical errors: `insufficient_balance`, `out_of_stock`, `validation_error`

### GET /gmail/orders

List Gmail orders

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `page` | query | integer | no | Page number |
| `per_page` | query | integer | no | 1–100 |
| `status` | query | string | no | pending \| completed \| failed \| refund_pending \| refunded \| refund_rejected |

```bash
curl -X GET 'https://api.adaotp.com/api/v1/gmail/orders' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "orders": [
            {
                "order_uuid": "c1d2…",
                "email": "someone123@gmail.com",
                "password": "••••••••",
                "status": "completed"
            }
        ]
    },
    "message": "OK"
}
```

### GET /gmail/orders/{uuid}

Get one Gmail order

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `uuid` | path | string | yes | order_uuid |

```bash
curl -X GET 'https://api.adaotp.com/api/v1/gmail/orders/c1d2e3f4-…' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "order_uuid": "c1d2…",
        "email": "someone123@gmail.com",
        "password": "••••••••",
        "status": "completed",
        "refund_status": null,
        "refundable": true
    },
    "message": "OK"
}
```

### POST /gmail/orders/{uuid}/refund

File a refund dispute. Send as multipart/form-data while `refundable` is true. A screenshot proving the problem is required.

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `uuid` | path | string | yes | order_uuid |
| `reason` | body | string | yes | 10–1000 characters |
| `proof` | body | file | yes | Screenshot: jpg/png/webp, max 5 MB |

```bash
curl -X POST 'https://api.adaotp.com/api/v1/gmail/orders/c1d2e3f4-…/refund' \
  -H 'X-API-Key: YOUR_API_KEY' \
  -F 'reason=Password is wrong, cannot sign in' \
  -F 'proof=@screenshot.png'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "refund_status": "pending"
    },
    "message": "OK"
}
```

### GET /gmail/orders/{uuid}/chat

Dispute chat link

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `uuid` | path | string | yes | order_uuid |

```bash
curl -X GET 'https://api.adaotp.com/api/v1/gmail/orders/c1d2e3f4-…/chat' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "url": "https://…"
    },
    "message": "OK"
}
```

## Email rental

Rent an email address to receive one verification code. Cancel for a full refund if the code never arrives.

### GET /email-rental/suggestions

Popular target sites

```bash
curl -X GET 'https://api.adaotp.com/api/v1/email-rental/suggestions' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "sites": [
            "tiktok.com",
            "facebook.com",
            "instagram.com",
            "x.com",
            "github.com"
        ]
    },
    "message": "OK"
}
```

### GET /email-rental/domains

Domains & prices for a site

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `site` | query | string | yes | Target site |

```bash
curl -X GET 'https://api.adaotp.com/api/v1/email-rental/domains?site=tiktok.com' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "domains": [
            {
                "name": "outlook.com",
                "count": 740,
                "price": 140,
                "completed": 24500
            },
            {
                "name": "gmx.com",
                "count": 730628,
                "price": 124,
                "completed": 11752
            }
        ],
        "used_domains": []
    },
    "message": "OK"
}
```

### POST /email-rental/orders

Rent an address. Charges your balance and returns the address. Poll GET /email-rental/orders/{uuid} until `code` is filled.

Accepts `Idempotency-Key` header.

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `site` | body | string | yes | Target site |
| `domain` | body | string | yes | Domain `name` from /email-rental/domains |

```bash
curl -X POST 'https://api.adaotp.com/api/v1/email-rental/orders' \
  -H 'X-API-Key: YOUR_API_KEY' \
  -H 'Idempotency-Key: 2f6c1b9e-1d0a-4c55-9a4e-6b8f2c7d1e03' \
  -H 'Content-Type: application/json' \
  -d '{"site":"tiktok.com","domain":"outlook.com"}'
```

Response (201):

```json
{
    "success": true,
    "data": {
        "order_uuid": "e5f6…",
        "site": "tiktok.com",
        "domain": "hotmail.com",
        "email": "abc123@outlook.com",
        "code": null,
        "price": 140,
        "status": "waiting",
        "cancellable": true
    },
    "message": "OK"
}
```

Typical errors: `insufficient_balance`, `service_unavailable`, `out_of_stock`

### GET /email-rental/orders

List rentals

```bash
curl -X GET 'https://api.adaotp.com/api/v1/email-rental/orders' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "orders": [
            {
                "order_uuid": "e5f6…",
                "email": "abc123@hotmail.com",
                "code": "482913",
                "status": "completed"
            }
        ]
    },
    "message": "OK"
}
```

### GET /email-rental/orders/{uuid}

Get one rental (poll for the code). Checks the mailbox each call. Poll every 5–10 seconds.

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `uuid` | path | string | yes | order_uuid |

```bash
curl -X GET 'https://api.adaotp.com/api/v1/email-rental/orders/e5f6a7b8-…' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "order_uuid": "e5f6…",
        "email": "abc123@hotmail.com",
        "code": "482913",
        "message": "Your TikTok code is 482913",
        "status": "completed",
        "cancellable": false
    },
    "message": "OK"
}
```

### POST /email-rental/orders/{uuid}/cancel

Cancel a rental (refund)

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `uuid` | path | string | yes | order_uuid |

```bash
curl -X POST 'https://api.adaotp.com/api/v1/email-rental/orders/e5f6a7b8-…/cancel' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "status": "canceled"
    },
    "message": "OK"
}
```

## WhatsApp Ready numbers

Numbers whose WhatsApp account is already active. Sign in with "Link with phone number / use your other phone": request a 6-digit code, enter it in WhatsApp, then confirm. Flow: ready → waiting_code → code_sent → completed. failed / canceled / refunded return the price to your balance.

### GET /wa-ready/info

Countries, prices & stock

```bash
curl -X GET 'https://api.adaotp.com/api/v1/wa-ready/info' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "enabled": true,
        "countries": [
            {
                "iso": "ID",
                "name": "Indonesia",
                "price": 13200,
                "stock": 25
            }
        ]
    },
    "message": "OK"
}
```

### POST /wa-ready/orders

Buy a WhatsApp number

Accepts `Idempotency-Key` header.

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `country` | body | string | yes | ISO 3166-1 alpha-2 from /wa-ready/info |

```bash
curl -X POST 'https://api.adaotp.com/api/v1/wa-ready/orders' \
  -H 'X-API-Key: YOUR_API_KEY' \
  -H 'Idempotency-Key: 2f6c1b9e-1d0a-4c55-9a4e-6b8f2c7d1e03' \
  -H 'Content-Type: application/json' \
  -d '{"country":"ID"}'
```

Response (201):

```json
{
    "success": true,
    "data": {
        "order": {
            "order_uuid": "3b9d…",
            "phone": "+6285860348151",
            "country": "ID",
            "price": 13200,
            "status": "ready"
        }
    },
    "message": "Number purchased"
}
```

Typical errors: `insufficient_balance`, `out_of_stock`, `provider_unavailable`

### GET /wa-ready/orders

List WhatsApp orders

```bash
curl -X GET 'https://api.adaotp.com/api/v1/wa-ready/orders' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "orders": [
            {
                "order_uuid": "3b9d…",
                "phone": "+6285860348151",
                "status": "completed"
            }
        ]
    },
    "message": "OK"
}
```

### GET /wa-ready/orders/{uuid}

Get order status (poll for the code). Poll every 3–5 seconds while `waiting_code`. Always use `latest_code`. Allowed actions are given by the `can_*` flags.

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `uuid` | path | string | yes | order_uuid |

```bash
curl -X GET 'https://api.adaotp.com/api/v1/wa-ready/orders/3b9d…' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "order": {
            "order_uuid": "3b9d…",
            "phone": "+6285860348151",
            "status": "code_sent",
            "latest_code": "482913",
            "can_confirm": true,
            "can_cancel": false,
            "can_dispute": true
        }
    },
    "message": "OK"
}
```

### POST /wa-ready/orders/{uuid}/request-code

Request the 6-digit code. Start the "link with phone number" flow in WhatsApp first, then call this.

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `uuid` | path | string | yes | order_uuid |

```bash
curl -X POST 'https://api.adaotp.com/api/v1/wa-ready/orders/3b9d…/request-code' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "order": {
            "status": "waiting_code"
        }
    },
    "message": "OK"
}
```

### POST /wa-ready/orders/{uuid}/confirm

Confirm successful sign-in

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `uuid` | path | string | yes | order_uuid |

```bash
curl -X POST 'https://api.adaotp.com/api/v1/wa-ready/orders/3b9d…/confirm' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "order": {
            "status": "completed"
        }
    },
    "message": "OK"
}
```

### POST /wa-ready/orders/{uuid}/cancel

Cancel (refund). Only while `can_cancel` is true (before a code was received).

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `uuid` | path | string | yes | order_uuid |

```bash
curl -X POST 'https://api.adaotp.com/api/v1/wa-ready/orders/3b9d…/cancel' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "order": {
            "status": "canceled"
        }
    },
    "message": "OK"
}
```

### POST /wa-ready/orders/{uuid}/dispute

File a complaint (refund). multipart/form-data, only while `can_dispute`. Approved → refunded; follow replies in the order `messages`.

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `uuid` | path | string | yes | order_uuid |
| `reason` | body | string | yes | 5–1000 characters |
| `image` | body | file | yes | Screenshot: jpg/png/webp, max 4 MB |

```bash
curl -X POST 'https://api.adaotp.com/api/v1/wa-ready/orders/3b9d…/dispute' \
  -H 'X-API-Key: YOUR_API_KEY' \
  -F 'reason=WhatsApp rejected the latest code' \
  -F 'image=@screenshot.png'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "order": {
            "dispute_status": "pending"
        }
    },
    "message": "OK"
}
```

### POST /wa-ready/orders/{uuid}/message

Reply in the complaint thread

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `uuid` | path | string | yes | order_uuid |
| `body` | body | string | yes | Up to 1000 characters |

```bash
curl -X POST 'https://api.adaotp.com/api/v1/wa-ready/orders/3b9d…/message' \
  -H 'X-API-Key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"body":"Screenshot attached above"}'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "order": {
            "…": "…"
        }
    },
    "message": "OK"
}
```

## Deposits & transactions

Top up your balance from code. Payment instructions (QR / virtual account / checkout URL) come back in the deposit response.

### GET /payment-methods

List payment methods

```bash
curl -X GET 'https://api.adaotp.com/api/v1/payment-methods' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": [
        {
            "id": 12,
            "name": "Qris Asia",
            "category_name": "Payment Gateway",
            "expiration_time": 5
        }
    ],
    "message": "OK"
}
```

### POST /deposits

Create a deposit (IDR). Returns the transaction with payment instructions (QR image as `qr_code_base64` or a `payment_url`). Poll GET /transactions/{uniqcode} for the status.

Accepts `Idempotency-Key` header.

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `amount` | body | integer | yes | IDR, minimum 10000 |
| `method` | body | integer | yes | Payment method id from /payment-methods |

```bash
curl -X POST 'https://api.adaotp.com/api/v1/deposits' \
  -H 'X-API-Key: YOUR_API_KEY' \
  -H 'Idempotency-Key: 2f6c1b9e-1d0a-4c55-9a4e-6b8f2c7d1e03' \
  -H 'Content-Type: application/json' \
  -d '{"amount":50000,"method":12}'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "uniqcode_tx": "TX…",
        "amount": 50000,
        "total_amount": 50123,
        "status": "pending",
        "qr_code_base64": "iVBOR…",
        "expires_at_iso": "2026-10-09T08:05:00+07:00"
    },
    "message": "OK"
}
```

### POST /deposits/crypto

Create a crypto deposit (USD)

Accepts `Idempotency-Key` header.

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `amount` | body | number | yes | USD, 1–10000 |

```bash
curl -X POST 'https://api.adaotp.com/api/v1/deposits/crypto' \
  -H 'X-API-Key: YOUR_API_KEY' \
  -H 'Idempotency-Key: 2f6c1b9e-1d0a-4c55-9a4e-6b8f2c7d1e03' \
  -H 'Content-Type: application/json' \
  -d '{"amount":10}'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "checkout_url": "https://…"
    },
    "message": "OK"
}
```

### GET /transactions

List deposits

```bash
curl -X GET 'https://api.adaotp.com/api/v1/transactions' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "transactions": [
            {
                "uniqcode_tx": "TX…",
                "type": "deposit",
                "amount": 50000,
                "fee": 0,
                "total_amount": 50123,
                "status": "success",
                "status_label": "Success",
                "payment_method": {
                    "…": "…"
                },
                "payment_url": null,
                "created_at_iso": "2026-10-09T08:00:00+07:00"
            }
        ],
        "pagination": {
            "…": "…"
        }
    },
    "message": "OK"
}
```

### GET /transactions/{uniqcode}

Get one deposit

| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `uniqcode` | path | string | yes | `uniqcode_tx` from the deposit / transaction list |

```bash
curl -X GET 'https://api.adaotp.com/api/v1/transactions/TX…' \
  -H 'X-API-Key: YOUR_API_KEY'
```

Response (200):

```json
{
    "success": true,
    "data": {
        "uniqcode_tx": "TX…",
        "amount": 50000,
        "total_amount": 50123,
        "status": "pending",
        "expires_in_seconds": 290,
        "qr_code_base64": "iVBOR…",
        "payment_url": null
    },
    "message": "OK"
}
```

## Error codes

Error response: `{"success": false, "message": "...", "error_code": "...", "request_id": "..."}`

| error_code | HTTP | Meaning |
|---|---|---|
| `unauthenticated` | 401 | No API key was sent. |
| `invalid_api_key` | 401 | The API key is wrong or the account is disabled. |
| `api_key_wrong_domain` | 401 | The key belongs to a different site. Use the site where you registered. |
| `validation_error` | 422 | A parameter is missing or invalid. Details per field are in `errors`. |
| `insufficient_balance` | 422 | Not enough balance. Top up and retry. |
| `out_of_stock` | 422 | No stock for this choice right now. Pick another country/server or retry in a few minutes. |
| `service_unavailable` | 422 | The service or target site is not supported right now. |
| `order_failed` | 422 | The provider rejected the order. Nothing was charged (or it was refunded). |
| `cancel_not_allowed_yet` | 422 | The order cannot be cancelled yet. Retry shortly. |
| `order_already_cancelled` | 422 | The order was already cancelled. |
| `provider_unavailable` | 422 | The upstream provider is temporarily unavailable or restricted. Retry later. |
| `upstream_error` | 422 | Any other failure reported by the provider. Read `message`. |
| `idempotency_key_reused` | 422 | This Idempotency-Key was already used with different parameters. |
| `order_not_found` | 404 | No such order for this API key. |
| `not_found` | 404 | Unknown endpoint or resource. |
| `product_unavailable` | 404 | This product is not offered on this site. |
| `idempotency_in_progress` | 409 | The first request with this Idempotency-Key is still running. Retry in a few seconds. |
| `rate_limited` | 429 | Too many requests. Wait and retry. |
| `server_error` | 500 | Unexpected error on our side. Retry; contact support with the request_id if it persists. |
