# AuthSMS API v1

> Buy virtual numbers, receive SMS verification codes and rent numbers programmatically.

The AuthSMS API is a JSON REST API. Every request is authenticated with your personal API key, every response is JSON with a `success` flag, and prices are in USD. Use it to automate account verification for WhatsApp, Telegram, Google and 1,000+ other services across 150+ countries.

- One-time numbers: buy, wait for the code, done. Refunds are automatic if no SMS arrives.
- Multiple SMS on the same number and the option to buy the same number again.
- Rentals for hours, days or weeks, with extension.
- Webhooks with HMAC signatures so you never have to poll.

Base URL: `https://authsms.net/api/v1`  
Web version of this document: https://authsms.net/api-docs  
Markdown version: https://authsms.net/api-docs.md

## Authentication

Create an API key on this page (sign in first). Send it in the `X-API-Key` header on every request. Keys do not expire; regenerate a key to revoke the old one immediately. Keep the key on your server and never ship it inside a mobile app or browser code.

```bash
curl "https://authsms.net/api/v1/me" -H "X-API-Key: YOUR_API_KEY"
```

## Conventions

- **Base URL:** `https://authsms.net/api/v1`
- **Format:** JSON request bodies (`Content-Type: application/json`) and JSON responses.
- **Success:** Every response includes `success: true`. The HTTP status is 200.
- **Errors:** Status 4xx/5xx with `success: false`, a machine-readable `error` code and a human `message`.
- **Money:** All prices and balances are USD numbers with up to 4 decimals, e.g. `0.42`.
- **Time:** Timestamps are ISO 8601 in UTC, e.g. `2026-10-16T18:04:11.000Z`.
- **IDs:** Number and rental ids are 24-character strings. Keep them; they are what you pass back to the API.
- **Rate limits:** Per key: 120 reads/min, 12 purchases/min. Over the limit you get `429 RATE_LIMITED`.

## Quickstart: receive a WhatsApp code in 4 calls

1. **Pick a country**: Ask for offers for `wa` and choose the cheapest country with stock. (`GET /offers`)
2. **Buy the number**: POST the service and country. Keep the returned `id` and show `phone` to the user. (`POST /numbers`)
3. **Wait for the code**: Poll `GET /numbers/{id}` every few seconds until `status` is `received`, or let a webhook call you. (`GET /numbers/{id}`)
4. **Finish**: Call `complete` when you are done, or `cancel` within the active window if the code never came (auto-refund happens anyway on expiry). (`POST /numbers/{id}/complete`)

## Number statuses

| Status | Meaning |
| --- | --- |
| `waiting` | Number is active and no SMS has arrived yet. Poll `GET /numbers/{id}` or wait for the webhook. |
| `received` | At least one code arrived. `code` holds the latest one, `messages` all of them. |
| `completed` | You marked the number as done. No more SMS will be delivered. |
| `cancelled` | You cancelled the number; the price was refunded. |
| `auto_cancelled` | No SMS arrived before the number expired; the price was refunded automatically. |

## Account

Who you are and how much you can spend.

### Get account

`GET /me`

Returns your username, email and current balance.

**Example request**

```bash
curl -X GET "https://authsms.net/api/v1/me" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Response**

```json
{
  "success": true,
  "user": {
    "username": "acme",
    "email": "dev@acme.io"
  },
  "balance": 12.5,
  "currency": "USD"
}
```

### Get balance

`GET /balance`

Lightweight balance check. Call it before buying in bulk.

**Example request**

```bash
curl -X GET "https://authsms.net/api/v1/balance" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Response**

```json
{
  "success": true,
  "balance": 12.5,
  "currency": "USD"
}
```

## Catalog

Countries, services, prices and stock. These endpoints work without an API key.

### List countries

`GET /countries`

All countries you can buy numbers in. Use `id` as the `country` parameter elsewhere.

_No API key required._

**Example request**

```bash
curl -X GET "https://authsms.net/api/v1/countries"
```

**Response**

```json
{
  "success": true,
  "countries": [
    {
      "id": "0",
      "name": "Russia"
    },
    {
      "id": "62",
      "name": "Turkey"
    },
    {
      "id": "187",
      "name": "United States"
    }
  ]
}
```

### List services

`GET /services`

Every service (app or website) you can receive codes for. Use `code` as the `service` parameter elsewhere.

_No API key required._

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `country` | query | string | no | Only services available in this country id. |

**Example request**

```bash
curl -X GET "https://authsms.net/api/v1/services?country=62"
```

**Response**

```json
{
  "success": true,
  "services": [
    {
      "code": "wa",
      "name": "WhatsApp"
    },
    {
      "code": "tg",
      "name": "Telegram"
    },
    {
      "code": "go",
      "name": "Google"
    }
  ]
}
```

### Get prices

`GET /prices`

Current price and stock per country and service. Filter by either or both.

_No API key required._

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `service` | query | string | no | Service code, e.g. `wa`. |
| `country` | query | string | no | Country id, e.g. `62`. |

**Example request**

```bash
curl -X GET "https://authsms.net/api/v1/prices?service=wa&country=62"
```

**Response**

```json
{
  "success": true,
  "prices": [
    {
      "country": "62",
      "service": "wa",
      "price": 0.42,
      "available": 1835
    },
    {
      "country": "187",
      "service": "wa",
      "price": 0.95,
      "available": 412
    }
  ]
}
```

### Get offers for a service

`GET /offers`

The easiest way to pick a country: every country with stock for one service, sorted by availability. Pass the `route` back when buying to lock in exactly this offer.

_No API key required._

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `service` | query | string | yes | Service code, e.g. `wa`. |

**Example request**

```bash
curl -X GET "https://authsms.net/api/v1/offers?service=wa"
```

**Response**

```json
{
  "success": true,
  "offers": [
    {
      "country": "62",
      "countryName": "Turkey",
      "price": 0.42,
      "available": 1835,
      "operator": null,
      "route": "rt_8f3a2c1d"
    },
    {
      "country": "187",
      "countryName": "United States",
      "price": 0.95,
      "available": 412,
      "operator": null,
      "route": "rt_8f3a2c1d"
    }
  ]
}
```

## Numbers

One-time numbers for receiving verification codes. The full lifecycle: buy, poll or webhook, complete (or cancel).

### Buy a number

`POST /numbers`

Reserves a number and charges your balance. The number stays active for the period shown in `expiresAt` (typically 20 minutes). If no SMS arrives it is refunded automatically.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `service` | body | string | yes | Service code from `/services`, e.g. `wa`. |
| `country` | body | string | yes | Country id from `/countries`, e.g. `62`. |
| `route` | body | string | no | Offer `route` from `/offers` to buy that exact offer. |
| `operator` | body | string | no | Mobile operator, when `/offers` lists one. |

**Example request**

```bash
curl -X POST "https://authsms.net/api/v1/numbers" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"service":"wa","country":"62"}'
```

**Request body**

```json
{
  "service": "wa",
  "country": "62"
}
```

**Response**

```json
{
  "success": true,
  "number": {
    "id": "66f1c2d3e4a5b6c7d8e9f0a1",
    "phone": "905381234567",
    "service": "wa",
    "serviceName": "WhatsApp",
    "country": "62",
    "countryName": "Turkey",
    "price": 0.42,
    "status": "waiting",
    "code": null,
    "text": null,
    "messages": [],
    "canRequestAnother": false,
    "awaitingAnother": false,
    "canReactivate": false,
    "canCancel": true,
    "expiresAt": "2026-10-16T18:24:00.000Z",
    "createdAt": "2026-10-16T18:04:00.000Z"
  },
  "balance": 12.08
}
```

> Enter the `phone` in the app you are verifying, then poll `GET /numbers/{id}` every 3 to 5 seconds or use a webhook.

### Get a number (poll for the code)

`GET /numbers/{id}`

Returns the current state. While the number is active, this call also checks upstream for new messages, so it is the only endpoint you need to poll.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | Number id from the purchase response. |

**Example request**

```bash
curl -X GET "https://authsms.net/api/v1/numbers/66f1c2d3e4a5b6c7d8e9f0a1" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Response**

```json
{
  "success": true,
  "number": {
    "id": "66f1c2d3e4a5b6c7d8e9f0a1",
    "phone": "905381234567",
    "service": "wa",
    "serviceName": "WhatsApp",
    "country": "62",
    "countryName": "Turkey",
    "price": 0.42,
    "status": "received",
    "code": "847291",
    "text": "Your WhatsApp code: 847-291",
    "messages": [
      {
        "code": "847291",
        "text": "Your WhatsApp code: 847-291",
        "sender": "WhatsApp",
        "receivedAt": "2026-10-16T18:04:10.000Z"
      }
    ],
    "canRequestAnother": true,
    "awaitingAnother": false,
    "canReactivate": true,
    "canCancel": false,
    "expiresAt": "2026-10-16T18:24:00.000Z",
    "createdAt": "2026-10-16T18:04:00.000Z"
  }
}
```

### List numbers

`GET /numbers`

Your numbers, newest first, with pagination.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `status` | query | string | no | One of `waiting`, `received`, `completed`, `cancelled`, `auto_cancelled`. |
| `service` | query | string | no | Filter by service code. |
| `country` | query | string | no | Filter by country id. |
| `page` | query | number | no | Page number, default 1. |
| `limit` | query | number | no | Items per page, 1 to 100, default 20. |

**Example request**

```bash
curl -X GET "https://authsms.net/api/v1/numbers?service=wa&country=62" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Response**

```json
{
  "success": true,
  "numbers": [
    {
      "id": "66f1c2d3e4a5b6c7d8e9f0a1",
      "phone": "905381234567",
      "service": "wa",
      "serviceName": "WhatsApp",
      "country": "62",
      "countryName": "Turkey",
      "price": 0.42,
      "status": "received",
      "code": "847291",
      "text": "Your WhatsApp code: 847-291",
      "messages": [
        {
          "code": "847291",
          "text": "Your WhatsApp code: 847-291",
          "sender": "WhatsApp",
          "receivedAt": "2026-10-16T18:04:10.000Z"
        }
      ],
      "canRequestAnother": true,
      "awaitingAnother": false,
      "canReactivate": true,
      "canCancel": false,
      "expiresAt": "2026-10-16T18:24:00.000Z",
      "createdAt": "2026-10-16T18:04:00.000Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 1,
    "totalPages": 1,
    "hasMore": false
  }
}
```

### Complete a number

`POST /numbers/{id}/complete`

Tell us you are done with a number that received a code. Frees the number early; no refund. Safe to call twice.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | Number id. |

**Example request**

```bash
curl -X POST "https://authsms.net/api/v1/numbers/66f1c2d3e4a5b6c7d8e9f0a1/complete" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Response**

```json
{
  "success": true,
  "number": {
    "id": "66f1c2d3e4a5b6c7d8e9f0a1",
    "phone": "905381234567",
    "service": "wa",
    "serviceName": "WhatsApp",
    "country": "62",
    "countryName": "Turkey",
    "price": 0.42,
    "status": "completed",
    "code": "847291",
    "text": "Your WhatsApp code: 847-291",
    "messages": [
      {
        "code": "847291",
        "text": "Your WhatsApp code: 847-291",
        "sender": "WhatsApp",
        "receivedAt": "2026-10-16T18:04:10.000Z"
      }
    ],
    "canRequestAnother": false,
    "awaitingAnother": false,
    "canReactivate": true,
    "canCancel": false,
    "expiresAt": "2026-10-16T18:24:00.000Z",
    "createdAt": "2026-10-16T18:04:00.000Z"
  }
}
```

### Cancel a number

`POST /numbers/{id}/cancel`

Cancels a number that has not received a code yet and refunds its price. Allowed 3 minutes after purchase.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | Number id. |

**Example request**

```bash
curl -X POST "https://authsms.net/api/v1/numbers/66f1c2d3e4a5b6c7d8e9f0a1/cancel" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Response**

```json
{
  "success": true,
  "refund": 0.42,
  "balance": 12.5,
  "number": {
    "id": "66f1c2d3e4a5b6c7d8e9f0a1",
    "phone": "905381234567",
    "service": "wa",
    "serviceName": "WhatsApp",
    "country": "62",
    "countryName": "Turkey",
    "price": 0.42,
    "status": "cancelled",
    "code": null,
    "text": null,
    "messages": [],
    "canRequestAnother": false,
    "awaitingAnother": false,
    "canReactivate": false,
    "canCancel": false,
    "expiresAt": null,
    "createdAt": "2026-10-16T18:04:00.000Z"
  }
}
```

**Errors:** `EARLY_CANCEL_DENIED`, `ALREADY_PROCESSED`

### Request another SMS

`POST /numbers/{id}/resend`

For a number that already received a code: ask for one more SMS on the same number (for example a second verification step). For a waiting number: ask the upstream network to resend. Watch `awaitingAnother` and `messages`.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | Number id. |

**Example request**

```bash
curl -X POST "https://authsms.net/api/v1/numbers/66f1c2d3e4a5b6c7d8e9f0a1/resend" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Response**

```json
{
  "success": true,
  "awaitingAnother": true,
  "number": {
    "id": "66f1c2d3e4a5b6c7d8e9f0a1",
    "phone": "905381234567",
    "service": "wa",
    "serviceName": "WhatsApp",
    "country": "62",
    "countryName": "Turkey",
    "price": 0.42,
    "status": "received",
    "code": "847291",
    "text": "Your WhatsApp code: 847-291",
    "messages": [
      {
        "code": "847291",
        "text": "Your WhatsApp code: 847-291",
        "sender": "WhatsApp",
        "receivedAt": "2026-10-16T18:04:10.000Z"
      }
    ],
    "canRequestAnother": false,
    "awaitingAnother": true,
    "canReactivate": true,
    "canCancel": false,
    "expiresAt": "2026-10-16T18:24:00.000Z",
    "createdAt": "2026-10-16T18:04:00.000Z"
  }
}
```

**Errors:** `RESEND_UNSUPPORTED`, `EARLY_RESEND_DENIED`

### Reactivation options

`GET /numbers/{id}/reactivate-options`

Prices for buying the same number again for a longer period. Handy when a service sends a second code later or you need to log in again.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | A number with status `received` or `completed`. |

**Example request**

```bash
curl -X GET "https://authsms.net/api/v1/numbers/66f1c2d3e4a5b6c7d8e9f0a1/reactivate-options" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Response**

```json
{
  "success": true,
  "phone": "905381234567",
  "options": [
    {
      "hours": 4,
      "price": 0.35
    },
    {
      "hours": 24,
      "price": 0.9
    },
    {
      "hours": 168,
      "price": 3.2
    }
  ]
}
```

### Buy the same number again

`POST /numbers/{id}/reactivate`

Buys the same phone number for one of the offered periods and returns a brand-new number object (new `id`).

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | Previous number id. |
| `hours` | body | number | yes | One of the `hours` values from reactivation options. |

**Example request**

```bash
curl -X POST "https://authsms.net/api/v1/numbers/66f1c2d3e4a5b6c7d8e9f0a1/reactivate" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"hours":24}'
```

**Request body**

```json
{
  "hours": 24
}
```

**Response**

```json
{
  "success": true,
  "number": {
    "id": "66f1c2d3e4a5b6c7d8e9f0b2",
    "phone": "905381234567",
    "service": "wa",
    "serviceName": "WhatsApp",
    "country": "62",
    "countryName": "Turkey",
    "price": 0.9,
    "status": "waiting",
    "code": null,
    "text": null,
    "messages": [],
    "canRequestAnother": false,
    "awaitingAnother": false,
    "canReactivate": false,
    "canCancel": true,
    "expiresAt": "2026-10-17T18:04:00.000Z",
    "createdAt": "2026-10-16T18:04:00.000Z"
  },
  "balance": 11.18
}
```

**Errors:** `NOT_REACTIVATABLE`, `BAD_DURATION`, `NO_NUMBERS`

## Rentals

Keep a number for hours, days or weeks and receive every SMS sent to it.

### Rental offers

`GET /rentals/offers`

Countries with rentable numbers for a service and the available periods.

_No API key required._

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `service` | query | string | yes | Service code, or `full` for any service. |
| `hours` | query | number | no | Rental period in hours; defaults to the shortest available. |

**Example request**

```bash
curl -X GET "https://authsms.net/api/v1/rentals/offers?service=wa&hours=72"
```

**Response**

```json
{
  "success": true,
  "enabled": true,
  "hours": 72,
  "periods": [
    24,
    72,
    168,
    720
  ],
  "offers": [
    {
      "country": "62",
      "countryName": "Turkey",
      "price": 3.1,
      "available": 240,
      "operator": null,
      "route": "rt_8f3a2c1d"
    }
  ]
}
```

### Rent a number

`POST /rentals`

Rents a number for the given period and charges your balance.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `service` | body | string | yes | Service code or `full`. |
| `country` | body | string | yes | Country id. |
| `hours` | body | number | yes | One of the `periods` from rental offers. |
| `route` | body | string | no | Offer `route` to rent that exact offer. |

**Example request**

```bash
curl -X POST "https://authsms.net/api/v1/rentals" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"service":"full","country":"62","hours":72}'
```

**Request body**

```json
{
  "service": "full",
  "country": "62",
  "hours": 72
}
```

**Response**

```json
{
  "success": true,
  "rental": {
    "id": "66f1d4e5f6a7b8c9d0e1f2a3",
    "phoneNumber": "905385551122",
    "service": "full",
    "serviceName": "Any service",
    "country": "62",
    "countryName": "Turkey",
    "operator": null,
    "periodHours": 72,
    "cost": 3.1,
    "status": "active",
    "startsAt": "2026-10-16T18:00:00.000Z",
    "expiresAt": "2026-10-19T18:00:00.000Z",
    "messages": [],
    "prolongHistory": [],
    "canProlong": true,
    "createdAt": "2026-10-16T18:00:00.000Z"
  },
  "balance": 9.4
}
```

### List rentals

`GET /rentals`

All your rentals, newest first.

**Example request**

```bash
curl -X GET "https://authsms.net/api/v1/rentals" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Response**

```json
{
  "success": true,
  "rentals": [
    {
      "id": "66f1d4e5f6a7b8c9d0e1f2a3",
      "phoneNumber": "905385551122",
      "service": "full",
      "serviceName": "Any service",
      "country": "62",
      "countryName": "Turkey",
      "operator": null,
      "periodHours": 72,
      "cost": 3.1,
      "status": "active",
      "startsAt": "2026-10-16T18:00:00.000Z",
      "expiresAt": "2026-10-19T18:00:00.000Z",
      "messages": [
        {
          "sender": "Instagram",
          "text": "Your code is 112233",
          "code": "112233",
          "receivedAt": "2026-10-16T19:12:00.000Z"
        }
      ],
      "prolongHistory": [],
      "canProlong": true,
      "createdAt": "2026-10-16T18:00:00.000Z"
    }
  ]
}
```

### Get a rental (messages)

`GET /rentals/{id}`

Current state and every SMS received so far. Active rentals are refreshed upstream on each call.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | Rental id. |

**Example request**

```bash
curl -X GET "https://authsms.net/api/v1/rentals/66f1c2d3e4a5b6c7d8e9f0a1" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Response**

```json
{
  "success": true,
  "rental": {
    "id": "66f1d4e5f6a7b8c9d0e1f2a3",
    "phoneNumber": "905385551122",
    "service": "full",
    "serviceName": "Any service",
    "country": "62",
    "countryName": "Turkey",
    "operator": null,
    "periodHours": 72,
    "cost": 3.1,
    "status": "active",
    "startsAt": "2026-10-16T18:00:00.000Z",
    "expiresAt": "2026-10-19T18:00:00.000Z",
    "messages": [
      {
        "sender": "Instagram",
        "text": "Your code is 112233",
        "code": "112233",
        "receivedAt": "2026-10-16T19:12:00.000Z"
      }
    ],
    "prolongHistory": [],
    "canProlong": true,
    "createdAt": "2026-10-16T18:00:00.000Z"
  }
}
```

### Extension options

`GET /rentals/{id}/prolong-options`

Prices for keeping the number longer.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | Active rental id. |

**Example request**

```bash
curl -X GET "https://authsms.net/api/v1/rentals/66f1c2d3e4a5b6c7d8e9f0a1/prolong-options" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Response**

```json
{
  "success": true,
  "expiresAt": "2026-10-19T18:00:00.000Z",
  "options": [
    {
      "hours": 24,
      "price": 1.2
    },
    {
      "hours": 72,
      "price": 3.1
    },
    {
      "hours": 168,
      "price": 6
    }
  ]
}
```

### Extend a rental

`POST /rentals/{id}/prolong`

Adds time to an active rental. The new `expiresAt` starts from the current expiry.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | Active rental id. |
| `hours` | body | number | yes | One of the `hours` values from extension options. |

**Example request**

```bash
curl -X POST "https://authsms.net/api/v1/rentals/66f1c2d3e4a5b6c7d8e9f0a1/prolong" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"hours":72}'
```

**Request body**

```json
{
  "hours": 72
}
```

**Response**

```json
{
  "success": true,
  "rental": {
    "id": "66f1d4e5f6a7b8c9d0e1f2a3",
    "phoneNumber": "905385551122",
    "service": "full",
    "serviceName": "Any service",
    "country": "62",
    "countryName": "Turkey",
    "operator": null,
    "periodHours": 144,
    "cost": 3.1,
    "status": "active",
    "startsAt": "2026-10-16T18:00:00.000Z",
    "expiresAt": "2026-10-22T18:00:00.000Z",
    "messages": [
      {
        "sender": "Instagram",
        "text": "Your code is 112233",
        "code": "112233",
        "receivedAt": "2026-10-16T19:12:00.000Z"
      }
    ],
    "prolongHistory": [
      {
        "hours": 72,
        "cost": 3.1,
        "createdAt": "2026-10-16T20:00:00.000Z"
      }
    ],
    "canProlong": true,
    "createdAt": "2026-10-16T18:00:00.000Z"
  },
  "price": 3.1,
  "balance": 6.3
}
```

### Cancel a rental

`POST /rentals/{id}/cancel`

Ends a rental early. Rentals are not refunded.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | Active rental id. |

**Example request**

```bash
curl -X POST "https://authsms.net/api/v1/rentals/66f1c2d3e4a5b6c7d8e9f0a1/cancel" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Response**

```json
{
  "success": true
}
```

## Webhooks

Get notified instead of polling.

### Get webhook

`GET /webhook`

Your current webhook URL and whether signing is enabled.

**Example request**

```bash
curl -X GET "https://authsms.net/api/v1/webhook" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Response**

```json
{
  "success": true,
  "url": "https://api.acme.io/hooks/authsms",
  "events": [
    "sms.received",
    "number.cancelled",
    "number.expired"
  ],
  "signing": true
}
```

### Set webhook

`PUT /webhook`

Registers (or replaces) your webhook URL. The signing `secret` is returned once; store it.

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `url` | body | string | yes | Public HTTPS URL. Private or local addresses are rejected. |

**Example request**

```bash
curl -X PUT "https://authsms.net/api/v1/webhook" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://api.acme.io/hooks/authsms"}'
```

**Request body**

```json
{
  "url": "https://api.acme.io/hooks/authsms"
}
```

**Response**

```json
{
  "success": true,
  "url": "https://api.acme.io/hooks/authsms",
  "secret": "whsec_2b7e151628aed2a6abf7158809cf4f3c",
  "events": [
    "sms.received",
    "number.cancelled",
    "number.expired"
  ]
}
```

**Errors:** `INVALID_URL`

### Send a test event

`POST /webhook/test`

Delivers a sample `sms.received` event (with `data.test: true`) to your URL.

**Example request**

```bash
curl -X POST "https://authsms.net/api/v1/webhook/test" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Response**

```json
{
  "success": true
}
```

### Remove webhook

`DELETE /webhook`

Stops all deliveries.

**Example request**

```bash
curl -X DELETE "https://authsms.net/api/v1/webhook" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Response**

```json
{
  "success": true
}
```

## Webhooks: payload and signature

Register an HTTPS URL and AuthSMS will POST a JSON event to it the moment an SMS arrives, so you do not have to poll. Each delivery is retried up to 3 times. Verify the signature before trusting the payload.

**Events**

| Event | When |
| --- | --- |
| `sms.received` | A code arrived on one of your numbers. `data.additional` is true for second and later messages. |
| `number.cancelled` | The number was cancelled upstream and refunded. |
| `number.expired` | The number expired without an SMS and was refunded. |

**Headers**

| Header | Value |
| --- | --- |
| `X-AuthSMS-Event` | Event type, e.g. `sms.received`. |
| `X-AuthSMS-Timestamp` | Unix seconds when the event was signed. |
| `X-AuthSMS-Signature` | `v1=` + HMAC-SHA256 of `"{timestamp}.{rawBody}"` using your webhook secret. |

**Payload**

```json
{
  "id": "evt_9f1c2d3e4a5b6c7d",
  "type": "sms.received",
  "createdAt": "2026-10-16T18:04:11.000Z",
  "data": {
    "numberId": "66f1c2d3e4a5b6c7d8e9f0a1",
    "phone": "905381234567",
    "service": "wa",
    "country": "62",
    "code": "847291",
    "text": "Your WhatsApp code: 847-291",
    "additional": false,
    "receivedAt": "2026-10-16T18:04:10.000Z"
  }
}
```

**Verify (Node.js)**

```js
import crypto from 'node:crypto'

export function verifyAuthSmsWebhook(rawBody, headers, secret) {
  const ts = headers['x-authsms-timestamp']
  const sig = (headers['x-authsms-signature'] || '').replace('v1=', '')
  const expected = crypto.createHmac('sha256', secret).update(`${ts}.${rawBody}`).digest('hex')
  const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300
  return fresh && crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))
}
```

## Error codes

| Code | HTTP | Meaning |
| --- | --- | --- |
| `INVALID_API_KEY` | 401 | The key is missing, malformed or was regenerated. |
| `INSUFFICIENT_BALANCE` | 400 | Top up your balance at https://authsms.net/payment. |
| `NO_NUMBERS` | 400 | No stock for that service in that country right now. Try another country or route. |
| `EARLY_CANCEL_DENIED` | 400 | Numbers can be cancelled 3 minutes after purchase. `remainingSeconds` tells you how long to wait. |
| `ALREADY_PROCESSED` | 400 | The number already received a code, was cancelled or completed. |
| `RESEND_UNSUPPORTED` | 400 | This number cannot receive another SMS. |
| `NOT_REACTIVATABLE` | 400 | Only numbers that received a code can be bought again. |
| `BAD_DURATION` | 400 | The requested period is not offered. `allowed` lists valid values. |
| `RENTAL_DISABLED` | 503 | Rentals are temporarily switched off. |
| `MAINTENANCE_MODE` | 503 | The service is under maintenance; retry in a few minutes. |
| `RATE_LIMITED` | 429 | Slow down and retry after a short pause. |
| `VALIDATION_ERROR` | 400 | A parameter is missing or has the wrong type; `message` says which. |

## Support

Questions: https://authsms.net/contact or open a ticket at https://authsms.net/tickets.
