# OxgelAPI — REST API Documentation

OxgelAPI is a unified REST API for renting virtual phone numbers and receiving SMS / OTP codes online, plus bulk SMS and SMM (social media marketing) services. It covers 200+ countries and 1000+ services such as WhatsApp, Telegram, Google, Facebook, Instagram, TikTok, OpenAI, Discord, Twitter/X and many more.

- **Base URL:** `https://oxgelapi.com/api/v1`
- **Authentication:** HTTP header `X-API-Key: OXGL-xxxxxxxxxxxx`
- **Public docs page:** `https://oxgelapi.com/docs.html` — no login required.
- **Machine-readable spec:** `https://oxgelapi.com/openapi.json`
- **Format:** JSON requests and responses; all amounts in **USD**.
- **Get your API key:** sign up at https://oxgelapi.com/register, then open https://oxgelapi.com/dashboard/api-keys.
- **Top up:** https://oxgelapi.com/dashboard/wallet (Mobile Money for Cameroon, crypto coming soon).

---

## Authentication

Every request must include your API key in the `X-API-Key` header. Alternatively pass it as an `?api_key=` query parameter (less recommended).

```bash
curl -H "X-API-Key: OXGL-YOUR-KEY-HERE" \
  https://oxgelapi.com/api/v1/balance
```

Errors:

| Status | Meaning |
|--------|---------|
| 401 `Missing X-API-Key header` | Header was not sent |
| 401 `Invalid or inactive API key` | Key is wrong, revoked, or disabled |
| 402 `Insufficient balance` | Top up your wallet |
| 403 `banned` | Account banned |
| 404 | Unknown endpoint or order id |

---

## Endpoints

### `GET /balance`

Returns the current wallet balance.

**Response**
```json
{ "balance": 12.45, "escrow": 0.85, "currency": "USD" }
```

---

### `GET /services`

Lists all supported services you can rent a number for.

**Response**
```json
[
  { "code": "wa", "name": "WhatsApp" },
  { "code": "tg", "name": "Telegram" },
  { "code": "go", "name": "Google / YouTube / Gmail" },
  { "code": "fb", "name": "Facebook" },
  { "code": "ig", "name": "Instagram" },
  { "code": "tk", "name": "TikTok" },
  { "code": "oi", "name": "OpenAI / ChatGPT" }
]
```

---

### `GET /countries`

Lists supported countries.

**Response**
```json
[
  { "code": "0",   "iso2": "RU", "name": "Russia" },
  { "code": "187", "iso2": "US", "name": "USA" },
  { "code": "16",  "iso2": "GB", "name": "United Kingdom" }
]
```

---

### `GET /prices?service=<code>&country=<code>`

Returns the current per-country price for a service.

**Query params**
- `service` *(required)* — service code from `/services`
- `country` *(optional)* — country code; omit to get all countries

**Response**
```json
[
  { "country": "187", "price": 0.18, "stock": 4 },
  { "country": "16",  "price": 0.22, "stock": 2 }
]
```

`price` is the final price you will be charged in USD (already includes margin and your loyalty discount if applicable). `stock` is how many operators currently have numbers available.

---

### `POST /numbers/buy`

Rents a number. Funds equal to `price` are moved from `balance` to `escrow` and an order is created.

**Body**
```json
{ "service": "wa", "country": "187", "operator": "any" }
```

- `service` *(required)*
- `country` *(required)*
- `operator` *(optional, default `"any"`)*

**Response**
```json
{
  "id": "5e8b...uuid",
  "order_code": "ORD-LX9F2A",
  "phone": "+15551234567",
  "expires_at": "2026-06-03T14:23:00.000Z",
  "cost": 0.18
}
```

Orders expire after **20 minutes** if no SMS is received. Unused funds in escrow are automatically refunded on expiry/cancel.

---

### `GET /numbers/status?id=<order_id>`

Poll this endpoint to check whether an SMS has arrived. Recommended interval: every 3–5 seconds.

**Response (still waiting)**
```json
{ "status": "waiting", "sms_code": null, "phone": "+15551234567" }
```

**Response (received)**
```json
{ "status": "received", "sms_code": "482913", "phone": "+15551234567" }
```

Possible `status` values: `waiting`, `received`, `cancelled`, `finished`, `expired`.

---

### `POST /numbers/cancel?id=<order_id>`

Cancels a waiting order and refunds the escrow to your balance. **Only allowed after 2 minutes** (provider rule).

**Response**
```json
{ "ok": true, "refunded": 0.18 }
```

---

### `POST /numbers/finish?id=<order_id>`

Marks an order as complete after you have used the SMS. This releases escrow as a final debit.

**Response**
```json
{ "ok": true }
```

---

### `POST /numbers/another?id=<order_id>`

Requests another SMS to the same number (some services send a second code). Order returns to `waiting` state.

**Response**
```json
{ "ok": true }
```

---

## Full integration examples

### Node.js (fetch)

```js
const API = "https://oxgelapi.com/api/v1";
const KEY = process.env.OXGEL_API_KEY;

async function call(path, opts = {}) {
  const r = await fetch(`${API}${path}`, {
    ...opts,
    headers: { "X-API-Key": KEY, "Content-Type": "application/json", ...(opts.headers || {}) },
  });
  if (!r.ok) throw new Error(`${r.status} ${await r.text()}`);
  return r.json();
}

// 1. Buy a WhatsApp number for USA
const order = await call("/numbers/buy", {
  method: "POST",
  body: JSON.stringify({ service: "wa", country: "187" }),
});
console.log("Got number:", order.phone);

// 2. Poll for the SMS
let code = null;
for (let i = 0; i < 60 && !code; i++) {
  await new Promise(r => setTimeout(r, 5000));
  const s = await call(`/numbers/status?id=${order.id}`);
  if (s.status === "received") code = s.sms_code;
}
console.log("SMS code:", code);

// 3. Finish the order
await call(`/numbers/finish?id=${order.id}`, { method: "POST" });
```

### Python (requests)

```python
import os, time, requests

API = "https://oxgelapi.com/api/v1"
H = {"X-API-Key": os.environ["OXGEL_API_KEY"]}

order = requests.post(f"{API}/numbers/buy",
    headers=H, json={"service": "wa", "country": "187"}).json()
print("Got number:", order["phone"])

code = None
for _ in range(60):
    time.sleep(5)
    s = requests.get(f"{API}/numbers/status", headers=H,
                     params={"id": order["id"]}).json()
    if s["status"] == "received":
        code = s["sms_code"]; break
print("SMS code:", code)

requests.post(f"{API}/numbers/finish", headers=H, params={"id": order["id"]})
```

### cURL

```bash
# Balance
curl -H "X-API-Key: $KEY" https://oxgelapi.com/api/v1/balance

# Buy
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
  -d '{"service":"wa","country":"187"}' \
  https://oxgelapi.com/api/v1/numbers/buy

# Status (poll)
curl -H "X-API-Key: $KEY" "https://oxgelapi.com/api/v1/numbers/status?id=ORDER_ID"
```

---

## Lovable integration prompt

Paste this into another Lovable project to wire OxgelAPI in:

> Integrate the OxgelAPI virtual-number REST API. Docs: https://oxgelapi.com/api-docs.md and OpenAPI spec: https://oxgelapi.com/openapi.json. Auth is the header `X-API-Key: OXGL-...` (store it as an edge-function secret called `OXGEL_API_KEY`, never expose it client-side). Build an edge function that proxies `POST /numbers/buy`, `GET /numbers/status`, `POST /numbers/cancel`, `POST /numbers/finish`. On the frontend show a service+country picker (fetched from `/services` and `/countries`), then a "Buy number" button that calls the edge function and polls `/status` every 4 seconds until an SMS code is returned.

---

## Support

- Email: support@oxgelapi.com
- Telegram: https://t.me/oxgelapi
- Status & changelog: https://oxgelapi.com/blog
