# piv.day API Reference

Полный справочник REST API piv.day. Содержит все эндпойнты, тела запросов, форматы ответов, коды ошибок и вебхуки. Скачано с https://piv.day/api/docs для использования с ИИ-ассистентами.

---

## Начало работы

REST API на Business-тарифе. Bearer-токены, JSON, идемпотентные эндпойнты, предсказуемые коды ошибок. Документация ниже описывает каждый эндпойнт с примером запроса и ответа.

### Base URL

```
https://app.piv.day/api/v1
```

Все эндпойнты живут под этим префиксом. Окружение одно — отдельных staging-доменов нет.

### Аутентификация

```
Authorization: Bearer YOUR_API_KEY
```

Ключи создаются в дашборде в разделе `Настройки → API Keys`. У каждого ключа — гранулярные разрешения (чтение номеров, отправка SMS, покупка прокси и т.д.). Скомпрометированный токен ротируется в один клик без перерегистрации команды.

### Аккаунт

**200 OK**
```
curl https://app.piv.day/api/v1/account \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**Один служебный эндпойнт — баланс и email текущего аккаунта. Удобно проверить, что ключ рабочий и аутентификация настроена правильно.**
```
{
  "success": true,
  "data": {
    "user_id": "usr-uuid-...",
    "balance": 150.50,
    "email": "u***@example.com",
    "team_id": null,
    "is_team_member": false
  }
}
```

GET /api/v1/account

### Формат ответа

```
{
  "success": true,
  "data": { ... }
}
```

Все ответы — JSON. При ошибке `success` = `false`, а тело содержит `error.code` и `error.message`.

### Rate limits

**100 запросов в минуту на каждый API-ключ. Лимит общий для всех эндпойнтов. Если упёрлись в потолок — пишите в Telegram-поддержку, поднимем под нагрузку без долгих согласований.

При превышении приходит `429 RATE_LIMITED` и заголовок `Retry-After` — сколько секунд подождать до следующего запроса.**
```
HTTP/1.1 429 Too Many Requests
Retry-After: 12

{
  "success": false,
  "error": {
    "code": "RATE_LIMITED",
    "message": "Rate limit exceeded, retry in 12s"
  }
}
```

429 Too Many Requests

## Номера

Покупка, продление, восстановление номеров. Приём и отправка SMS. Запуск Google QR-верификации. Подписка на события через вебхуки.

### Список стран и цен

`GET /api/v1/numbers/countries`

Возвращает страны, доступные для покупки, с актуальной ценой и направлениями SMS. Все цены — итоговые, с учётом скидки вашей подписки.

**Поля ответа**

| Поле | Тип | Описание |
| --- | --- | --- |
| `country_code` | string | Двухбуквенный ISO-код страны (например `SE`). |
| `price_per_month` | number | Итоговая цена для вашего тарифа — то, что реально спишется при покупке. Если у вас Premium или Business, скидка уже включена. |
| `base_price` | number | Цена без скидок (Free-тариф). Возвращается для сравнения — увидеть, сколько экономит подписка. |
| `can_send_sms` | boolean | Можно ли с этого номера отправлять исходящие SMS. |
| `can_receive_sms` | boolean | Можно ли принимать входящие SMS. |
| `sms_send_price` | number\|null | Цена за исходящее SMS — тоже с учётом тарифа. `null`, если отправка из этой страны недоступна. |

**curl**
```bash
curl https://app.piv.day/api/v1/numbers/countries \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**200 OK**
```json
{
  "success": true,
  "data": [
    {
      "country_code": "SE",
      "price_per_month": 4.00,
      "base_price": 5.00,
      "can_send_sms": true,
      "can_receive_sms": true,
      "sms_send_price": 0.25
    },
    {
      "country_code": "GB",
      "price_per_month": 3.00,
      "base_price": 3.00,
      "can_send_sms": true,
      "can_receive_sms": true,
      "sms_send_price": 0.20
    }
  ]
}
```

### Список номеров аккаунта

`GET /api/v1/numbers`

Возвращает страницу номеров аккаунта с фильтрами по стране, статусу и поиском по номеру или кастомному имени.

**Query-параметры**

| Поле | Тип | Описание |
| --- | --- | --- |
| `limit` | integer | Количество записей на странице (по умолчанию 50, максимум 200). |
| `offset` | integer | Смещение для пагинации. |
| `country` | string | ISO-код страны для фильтра. |
| `status` | string | Один из `active`, `expired`, `pending_restore`. |
| `search` | string | Подстрока для поиска по номеру или кастомному имени. |

**curl**
```bash
curl "https://app.piv.day/api/v1/numbers?country=SE&status=active&limit=10" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "numbers": [
      {
        "piv_num_id": "vzPA1-kHKSg-EAL7e-Jqd3o",
        "phone_number": "+46764794425",
        "country_code": "SE",
        "status": "active",
        "created_at": "2026-05-01T10:00:00Z",
        "expires_at": "2026-05-31T10:00:00Z",
        "auto_renew": false,
        "custom_name": "Office line",
        "purchased_at": "2026-05-01T10:00:00Z",
        "next_renewal_date": "2026-05-31T10:00:00Z",
        "tags": ["support"],
        "can_send_sms": true,
        "can_receive_sms": true
      }
    ],
    "pagination": { "total": 1, "limit": 10, "offset": 0 }
  }
}
```

### Один номер по ID

`GET /api/v1/numbers/{piv_num_id}`

Полная карточка номера: статус, даты, авто-продление, теги, разрешённые SMS-направления.

**Ошибки**

| Код | HTTP | Когда срабатывает |
| --- | --- | --- |
| `NUMBER_NOT_FOUND` | 404 | Номер не найден или не принадлежит аккаунту. |

**curl**
```bash
curl https://app.piv.day/api/v1/numbers/vzPA1-kHKSg-EAL7e-Jqd3o \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "piv_num_id": "vzPA1-kHKSg-EAL7e-Jqd3o",
    "phone_number": "+46764794425",
    "country_code": "SE",
    "status": "active",
    "created_at": "2026-05-01T10:00:00Z",
    "expires_at": "2026-05-31T10:00:00Z",
    "auto_renew": false,
    "custom_name": "Office line",
    "purchased_at": "2026-05-01T10:00:00Z",
    "next_renewal_date": "2026-05-31T10:00:00Z",
    "tags": ["support"],
    "can_send_sms": true,
    "can_receive_sms": true
  }
}
```

### Покупка номера

`POST /api/v1/numbers/purchase`

Покупает один номер выбранной страны на указанный срок. Сумма списывается с баланса аккаунта. Возвращает `piv_num_id`, который дальше используется во всех операциях с номером.

**Тело запроса**

| Поле | Тип | Описание |
| --- | --- | --- |
| `country_code` * | string | ISO-код страны. |
| `duration_months` * | integer | Срок аренды в месяцах (минимум 1). |
| `auto_renew` * | boolean | Включить ли авто-продление сразу после покупки. |
| `custom_name` | string | Опциональное человекочитаемое имя для номера. |

**Ошибки**

| Код | HTTP | Когда срабатывает |
| --- | --- | --- |
| `COUNTRY_NOT_AVAILABLE` | 400 | Страна недоступна или для неё нет цен. |
| `NO_NUMBERS_AVAILABLE` | 400 | В указанной стране сейчас нет свободных номеров. |
| `INSUFFICIENT_BALANCE` | 402 | На балансе не хватает средств для покупки. |
| `VALIDATION_ERROR` | 400 | Невалидные поля в теле запроса. |

**curl**
```bash
curl -X POST https://app.piv.day/api/v1/numbers/purchase \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "country_code": "SE",
    "duration_months": 1,
    "auto_renew": false,
    "custom_name": "My Sweden Number"
  }'
```

**200 OK**
```json
{
  "success": true,
  "cost": 5.00,
  "numbers": [
    {
      "piv_num_id": "vzPA1-kHKSg-EAL7e-Jqd3o",
      "country_code": "SE",
      "phone_number": "+46764794425",
      "created_at": "2026-05-01T10:00:00Z",
      "expires_at": "2026-05-31T10:00:00Z",
      "auto_renew": false,
      "custom_name": "My Sweden Number"
    }
  ]
}
```

### Продлить номер

`POST /api/v1/numbers/{piv_num_id}/renew`

Продление активного номера на указанный срок. Стоимость списывается с баланса в момент вызова.

**Тело запроса**

| Поле | Тип | Описание |
| --- | --- | --- |
| `duration_months` * | integer | На сколько месяцев продлить. |

**Ошибки**

| Код | HTTP | Когда срабатывает |
| --- | --- | --- |
| `NUMBER_NOT_FOUND` | 404 | Номер не найден или не принадлежит аккаунту. |
| `COUNTRY_NOT_AVAILABLE` | 400 | Для страны номера не найдены цены. |
| `INSUFFICIENT_BALANCE` | 402 | Не хватает средств для продления. |

**curl**
```bash
curl -X POST https://app.piv.day/api/v1/numbers/vzPA1-kHKSg-EAL7e-Jqd3o/renew \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "duration_months": 1 }'
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "piv_num_id": "vzPA1-kHKSg-EAL7e-Jqd3o",
    "phone_number": "+46764794425",
    "old_expires_at": "2026-05-31T10:00:00Z",
    "new_expires_at": "2026-06-30T10:00:00Z",
    "cost": 5.00
  }
}
```

### Обновить номер

`PATCH /api/v1/numbers/{piv_num_id}`

Сейчас редактируется только кастомное имя номера.

**Тело запроса**

| Поле | Тип | Описание |
| --- | --- | --- |
| `custom_name` * | string | Новое имя номера. |

**Ошибки**

| Код | HTTP | Когда срабатывает |
| --- | --- | --- |
| `NUMBER_NOT_FOUND` | 404 | Номер не найден или не принадлежит аккаунту. |
| `VALIDATION_ERROR` | 400 | Невалидное значение в теле запроса. |

**curl**
```bash
curl -X PATCH https://app.piv.day/api/v1/numbers/vzPA1-kHKSg-EAL7e-Jqd3o \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "custom_name": "Support line" }'
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "piv_num_id": "vzPA1-kHKSg-EAL7e-Jqd3o",
    "phone_number": "+46764794425",
    "country_code": "SE",
    "status": "active",
    "custom_name": "Support line",
    "auto_renew": false,
    "expires_at": "2026-05-31T10:00:00Z",
    "tags": []
  }
}
```

### Управление авто-продлением

`PATCH /api/v1/numbers/{piv_num_id}/auto-renewal`

Включает или выключает авто-продление номера. Когда включено — продление списывается с баланса автоматически за 24 часа до истечения. Если средств не хватит, номер истечёт; вернуть его можно через `POST /numbers/restore` в течение 7 дней.

**Тело запроса**

| Поле | Тип | Описание |
| --- | --- | --- |
| `auto_renew` * | boolean | Новое значение флага авто-продления. |

**curl**
```bash
curl -X PATCH https://app.piv.day/api/v1/numbers/vzPA1-kHKSg-EAL7e-Jqd3o/auto-renewal \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "auto_renew": true }'
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "piv_num_id": "vzPA1-kHKSg-EAL7e-Jqd3o",
    "phone_number": "+46764794425",
    "auto_renew": true
  }
}
```

### Восстановить просроченные номера

`POST /api/v1/numbers/restore`

Возвращает просроченные номера в течение 7-дневного окна. Передайте массив `piv_num_id` — номера вернутся с сохранением SMS-истории и настроек. Стоимость восстановления выше, чем покупки нового номера (включён множитель восстановления) — точные цифры видны в дашборде перед подтверждением. Финальный статус по каждому номеру придёт на вебхук `number.restore_completed`; за неуспешные деньги автоматически возвращаются на баланс.

**Тело запроса**

| Поле | Тип | Описание |
| --- | --- | --- |
| `piv_num_ids` * | string[] | Массив ID номеров для восстановления. |

**Ошибки**

| Код | HTTP | Когда срабатывает |
| --- | --- | --- |
| `NO_RESTORABLE_NUMBERS` | 404 | Ни один из переданных номеров нельзя восстановить (истёк 7-дневный срок или номер не ваш). |
| `INSUFFICIENT_BALANCE` | 402 | Не хватает средств на оплату восстановления. |

**curl**
```bash
curl -X POST https://app.piv.day/api/v1/numbers/restore \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "piv_num_ids": [
      "vzPA1-kHKSg-EAL7e-Jqd3o",
      "abc12-defgh-ijklm-nopqr"
    ]
  }'
```

**200 OK**
```json
{
  "success": true,
  "queued": 2,
  "skipped": 0,
  "total_charged": 9.00,
  "numbers": [
    {
      "piv_num_id": "vzPA1-kHKSg-EAL7e-Jqd3o",
      "phone_number": "+46764794425",
      "status": "pending"
    }
  ]
}
```

### История SMS по номеру

`GET /api/v1/numbers/{piv_num_id}/sms`

Возвращает входящие и исходящие сообщения по номеру в обратном хронологическом порядке.

**Query-параметры**

| Поле | Тип | Описание |
| --- | --- | --- |
| `limit` | integer | Сколько сообщений вернуть (по умолчанию 50, максимум 200). |
| `offset` | integer | Смещение для пагинации. |

**curl**
```bash
curl "https://app.piv.day/api/v1/numbers/vzPA1-kHKSg-EAL7e-Jqd3o/sms?limit=20" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "messages": [
      {
        "id": "42",
        "from_number": "+46764794425",
        "to_number": "+14155551234",
        "message_body": "Hello from piv.day",
        "direction": "outbound",
        "status": "delivered",
        "received_at": "2026-05-22T11:30:00Z"
      },
      {
        "id": "41",
        "from_number": "+14155551234",
        "to_number": "+46764794425",
        "message_body": "Hey, got your message!",
        "direction": "inbound",
        "status": "received",
        "received_at": "2026-05-22T11:35:00Z"
      }
    ],
    "pagination": { "total": 2, "limit": 20, "offset": 0 }
  }
}
```

### Отправить SMS

`POST /api/v1/numbers/{piv_num_id}/sms/send`

Доступно для стран, где разрешена исходящая отправка (например CA, GB, SE). Стоимость сообщения списывается с баланса в момент отправки.

**Тело запроса**

| Поле | Тип | Описание |
| --- | --- | --- |
| `to_number` * | string | Номер получателя в международном формате (E.164). |
| `message_body` * | string | Текст сообщения. Поддерживаются GSM-7 и UCS-2. |

**Ошибки**

| Код | HTTP | Когда срабатывает |
| --- | --- | --- |
| `NUMBER_NOT_FOUND` | 404 | Номер не найден или не принадлежит аккаунту. |
| `NUMBER_EXPIRED` | 403 | Номер уже истёк. |
| `NUMBER_NOT_ACTIVE` | 400 | Номер сейчас в состоянии, не разрешающем отправку. |
| `INSUFFICIENT_BALANCE` | 402 | Не хватает средств для отправки. |
| `INVALID_MESSAGE_FORMAT` | 400 | Тело сообщения превышает допустимую длину или содержит запрещённые символы. |

**curl**
```bash
curl -X POST https://app.piv.day/api/v1/numbers/vzPA1-kHKSg-EAL7e-Jqd3o/sms/send \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to_number": "+14155551234",
    "message_body": "Hello from piv.day"
  }'
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "message_id": "42",
    "from_number": "+46764794425",
    "to_number": "+14155551234",
    "message_body": "Hello from piv.day",
    "status": "queued",
    "created_at": "2026-05-22T11:30:00Z"
  }
}
```

### Запуск Google QR-верификации

`POST /api/v1/numbers/{piv_num_id}/verify`

Запускает Google QR-верификацию по присланному URL. Результат — успех или ошибка — придёт на вебхук verify.completed или verify.failed. Стоимость списывается с баланса в момент запуска.

**Тело запроса**

| Поле | Тип | Описание |
| --- | --- | --- |
| `gv_url` * | string | Полный URL Google-верификации (берётся со страницы Google). |

**Ошибки**

| Код | HTTP | Когда срабатывает |
| --- | --- | --- |
| `NUMBER_NOT_FOUND` | 404 | Номер не найден или не ваш. |
| `NUMBER_NOT_ACTIVE` | 400 | Номер не в активном статусе. |
| `SMS_DISABLED` | 400 | Отправка SMS отключена для этого номера. |
| `INSUFFICIENT_BALANCE` | 402 | Не хватает средств для верификации. |
| `PROXY_DEAD` | 502 | Прокси недоступен — баланс возвращён. |
| `QUEUE_FULL` | 503 | Сервер занят, попробуйте позже — баланс возвращён. |
| `SERVER_UNAVAILABLE` | 503 | Сервер автоматизации недоступен — баланс возвращён. |

**curl**
```bash
curl -X POST https://app.piv.day/api/v1/numbers/vzPA1-kHKSg-EAL7e-Jqd3o/verify \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "gv_url": "https://gv.google.com/..." }'
```

**202 Accepted**
```json
{
  "success": true,
  "message": "Verification initiated"
}
```

## Прокси

Резидентский IPv6 в десятках стран. Покупка партиями, продление, Restore с теми же логином и паролем, экспорт в нужном формате.

### Список серверов

`GET /api/v1/proxy/servers`

Список доступных прокси-серверов с ценами.

**curl**
```bash
curl https://app.piv.day/api/v1/proxy/servers \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "servers": [
      {
        "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "name": "EU-DE-01",
        "country": "DE",
        "socks5_port": 1080,
        "http_port": 3128,
        "price_per_proxy": 0.50
      },
      {
        "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
        "name": "EU-NL-01",
        "country": "NL",
        "socks5_port": 1080,
        "http_port": 3128,
        "price_per_proxy": 0.45
      }
    ]
  }
}
```

### Список заказов

`GET /api/v1/proxy/orders`

Список ваших заказов прокси с возможностью фильтрации по статусу или поисковому запросу.

**Query-параметры**

| Поле | Тип | Описание |
| --- | --- | --- |
| `limit` | integer | Количество записей. По умолчанию: 100, максимум: 500. |
| `offset` | integer | Смещение для пагинации. |
| `status` | string | Фильтр по статусу: `active`, `expired`. |
| `search` | string | Поиск по заказу. |

**curl**
```bash
curl "https://app.piv.day/api/v1/proxy/orders?status=active&limit=20" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "orders": [
      {
        "id": "ord-uuid-...",
        "country": "DE",
        "quantity": 10,
        "price_per_proxy": 0.50,
        "price_total": 5.00,
        "status": "active",
        "purchased_at": "2026-01-01T00:00:00Z",
        "expires_at": "2026-02-01T00:00:00Z"
      }
    ],
    "pagination": { "total": 1, "limit": 20, "offset": 0 }
  }
}
```

### Один заказ

`GET /api/v1/proxy/orders/{id}`

Получить детали конкретного заказа, включая список прокси-учётных данных.

**curl**
```bash
curl https://app.piv.day/api/v1/proxy/orders/ord-uuid-... \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "order": {
      "id": "ord-uuid-...",
      "country": "DE",
      "quantity": 10,
      "price_per_proxy": 0.50,
      "price_total": 5.00,
      "status": "active",
      "purchased_at": "2026-01-01T00:00:00Z",
      "expires_at": "2026-02-01T00:00:00Z",
      "created_at": "2026-01-01T00:00:00Z",
      "items": [
        {
          "login": "user1",
          "password": "pass1",
          "host": "185.1.2.3",
          "socks5_port": 1080,
          "http_port": 3128,
          "ipv6": "2a00:1:2:3::1"
        }
      ]
    }
  }
}
```

### Купить прокси

`POST /api/v1/proxy/purchase`

Купить прокси на выбранном сервере. Один запрос создаёт один заказ с N прокси (до 500). Bulk-заказов нет — при необходимости вызывайте метод повторно.

**Тело запроса**

| Поле | Тип | Описание |
| --- | --- | --- |
| `server_id` * | string | ID сервера из `GET /proxy/servers`. |
| `quantity` * | integer | Сколько прокси купить (1–500). |
| `months` * | integer | Срок аренды в месяцах (1–12). |

**Ошибки**

| Код | HTTP | Когда срабатывает |
| --- | --- | --- |
| `INSUFFICIENT_BALANCE` | 402 | Не хватает средств. |
| `NOT_FOUND` | 404 | Прокси-сервер не найден или неактивен. |
| `VALIDATION_ERROR` | 400 | Некорректное тело запроса. |

**curl**
```bash
curl -X POST https://app.piv.day/api/v1/proxy/purchase \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "server_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "quantity": 5,
    "months": 1
  }'
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "order": {
      "id": "ord-uuid-...",
      "country": "DE",
      "quantity": 5,
      "price_total": 2.50,
      "status": "active",
      "expires_at": "2026-02-01T00:00:00Z",
      "created_at": "2026-01-01T00:00:00Z",
      "items": [
        {
          "login": "user1",
          "password": "pass1",
          "host": "185.1.2.3",
          "socks5_port": 1080,
          "http_port": 3128,
          "ipv6": "2a00:1:2:3::1"
        },
        {
          "login": "user2",
          "password": "pass2",
          "host": "185.1.2.3",
          "socks5_port": 1080,
          "http_port": 3128,
          "ipv6": "2a00:1:2:3::2"
        }
      ]
    }
  }
}
```

### Продлить заказ

`POST /api/v1/proxy/orders/{id}/renew`

Продлить активный заказ прокси на дополнительное количество месяцев.

**Тело запроса**

| Поле | Тип | Описание |
| --- | --- | --- |
| `months` * | integer | Сколько месяцев добавить. |

**curl**
```bash
curl -X POST https://app.piv.day/api/v1/proxy/orders/ord-uuid-.../renew \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "months": 1 }'
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "order_id": "ord-uuid-...",
    "cost": 5.00,
    "new_expires_at": "2026-03-01T00:00:00Z"
  }
}
```

### Restore просроченного заказа

`POST /api/v1/proxy/orders/{id}/restore`

Восстановить истёкший заказ прокси без перепокупки. Логин, пароль, IPv6-адреса, страна и привязки — те же. Срок продлевается на 1 месяц. Антидетект перенастраивать не надо.

**curl**
```bash
curl -X POST https://app.piv.day/api/v1/proxy/orders/ord-uuid-.../restore \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "order_id": "ord-uuid-...",
    "quantity": 10,
    "total_cost": 5.00,
    "expires_at": "2026-03-01T00:00:00Z"
  }
}
```

### Экспорт списка прокси

`GET /api/v1/proxy/orders/{id}/export`

Экспортировать учётные данные прокси заказа в виде текстового списка (login:password@host:port).

**Query-параметры**

| Поле | Тип | Описание |
| --- | --- | --- |
| `format` | string | Формат экспорта: `socks5`, `http` или `both` (по умолчанию `socks5`). |

**curl**
```bash
curl "https://app.piv.day/api/v1/proxy/orders/ord-uuid-.../export?format=socks5" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "content": "user1:pass1@1.2.3.4:1080\nuser2:pass2@1.2.3.4:1080",
    "filename": "piv-day-proxy-ord-uuid--socks5.txt",
    "format": "socks5",
    "count": 2
  }
}
```

## Домены

Поиск и регистрация без KYC, автоматический Cloudflare и SSL, управление DNS-записями и NS-серверами через API.

### Проверка доступности

`GET /api/v1/domains/search`

Проверить доступность и стоимость регистрации домена.

**Query-параметры**

| Поле | Тип | Описание |
| --- | --- | --- |
| `q` * | string | Имя домена для поиска, например `mysite.com`. |

**curl**
```bash
curl "https://app.piv.day/api/v1/domains/search?q=mysite.com" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "domain": "mysite.com",
    "available": true,
    "create_price": 12.50,
    "renew_price": 12.50,
    "currency": "USD"
  }
}
```

### Список доменов

`GET /api/v1/domains`

Список ваших зарегистрированных доменов с возможностью фильтрации.

**Query-параметры**

| Поле | Тип | Описание |
| --- | --- | --- |
| `limit` | integer | Количество записей. По умолчанию: 100, максимум: 500. |
| `offset` | integer | Смещение для пагинации. |
| `status` | string | Статус домена: `active`, `pending`, `expired`. |
| `cloudflare` | string | Фильтр по статусу Cloudflare: `true` или `false`. |
| `auto_renew` | string | Фильтр по автопродлению: `true` или `false`. |
| `search` | string | Поиск по доменному имени. |

**curl**
```bash
curl "https://app.piv.day/api/v1/domains?status=active&limit=20" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "domains": [
      {
        "id": "dom-uuid-...",
        "domain_name": "mysite.com",
        "status": "active",
        "registered_at": "2026-01-01T00:00:00Z",
        "expires_at": "2027-01-01T00:00:00Z",
        "auto_renew": true,
        "cloudflare_enabled": true,
        "cloudflare_status": "active",
        "ssl_type": "lets_encrypt",
        "ssl_status": "active",
        "ssl_mode": "full",
        "ssl_expires_at": "2026-04-01T00:00:00Z",
        "created_at": "2026-01-01T00:00:00Z",
        "updated_at": "2026-01-01T00:00:00Z"
      }
    ],
    "pagination": { "total": 1, "limit": 20, "offset": 0 }
  }
}
```

### Регистрация домена

`POST /api/v1/domains`

Зарегистрировать новый домен. Запрос асинхронный — возвращает `queue_id` для отслеживания. Cloudflare ВКЛ: поле `nameservers` передавать нельзя, можно опционально передать `dns_records` и `ssl_mode`. Cloudflare ВЫКЛ: поля `dns_records` и `ssl_mode` передавать нельзя, `nameservers` обязательно (не менее 2). NS-серверы Cloudflare мы никогда не раскрываем.

**Тело запроса**

| Поле | Тип | Описание |
| --- | --- | --- |
| `domain` * | string | Имя домена для регистрации, например `mysite.com`. |
| `period` * | integer | Срок регистрации в годах (1–10). |
| `cloudflare` * | boolean | Подключить домен к Cloudflare автоматически. |
| `auto_renew` * | boolean | Включить автоматическое продление. |
| `ssl_mode` | string | `flexible` \| `full` \| `strict`. Только при `cloudflare: true`. |
| `nameservers` | string[] | Обязательно при `cloudflare: false` (≥2 NS). Запрещено при `cloudflare: true`. |
| `dns_records` | object[] | Начальные DNS-записи. Только при `cloudflare: true`. |

**Ошибки**

| Код | HTTP | Когда срабатывает |
| --- | --- | --- |
| `DOMAIN_NOT_AVAILABLE` | 400 | Домен недоступен для регистрации. |
| `INSUFFICIENT_BALANCE` | 402 | Не хватает средств. |
| `VALIDATION_ERROR` | 400 | Некорректное тело запроса. |

**Cloudflare ВКЛ**
```bash
curl -X POST https://app.piv.day/api/v1/domains \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "mysite.com",
    "period": 1,
    "cloudflare": true,
    "auto_renew": true,
    "ssl_mode": "full",
    "dns_records": [
      { "type": "A", "name": "@", "content": "1.2.3.4", "proxied": true }
    ]
  }'
```

**Cloudflare ВЫКЛ — свои NS**
```bash
curl -X POST https://app.piv.day/api/v1/domains \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "mysite.com",
    "period": 1,
    "cloudflare": false,
    "auto_renew": false,
    "nameservers": ["ns1.myhost.com", "ns2.myhost.com"]
  }'
```

**202 Accepted**
```json
{
  "success": true,
  "data": {
    "queue_id": "que-uuid-...",
    "domain": {
      "id": "dom-uuid-...",
      "domain_name": "mysite.com",
      "status": "purchasing",
      "period": 1,
      "cloudflare_enabled": true,
      "auto_renew": true,
      "ssl_mode": "full",
      "created_at": "2026-01-01T00:00:00Z"
    }
  }
}
```

### Статус задачи регистрации

`GET /api/v1/domains/queue/{id}`

Проверить статус записи очереди регистрации или продления домена. При статусе `completed` в ответе сразу полная карточка домена — отдельный запрос к `/domains/{id}` не нужен.

**curl**
```bash
curl https://app.piv.day/api/v1/domains/queue/que-uuid-... \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**pending / processing**
```json
{
  "success": true,
  "data": {
    "queue_id": "que-uuid-...",
    "domain": "mysite.com",
    "status": "pending"
  }
}
```

**completed — полная карточка**
```json
{
  "success": true,
  "data": {
    "queue_id": "que-uuid-...",
    "status": "completed",
    "domain": {
      "id": "dom-uuid-...",
      "domain_name": "mysite.com",
      "status": "active",
      "registered_at": "2026-01-01T12:00:00Z",
      "expires_at": "2027-01-01T12:00:00Z",
      "auto_renew": true,
      "cloudflare_enabled": true,
      "cloudflare_status": "active",
      "ssl_type": "lets_encrypt",
      "ssl_status": "active",
      "ssl_mode": "full",
      "ssl_expires_at": "2026-04-01T00:00:00Z",
      "created_at": "2026-01-01T00:00:00Z",
      "updated_at": "2026-01-01T12:00:00Z",
      "dns_records": [
        { "name": "@", "type": "A", "content": "1.2.3.4", "ttl": 1, "priority": null, "proxied": true }
      ]
    }
  }
}
```

### Один домен

`GET /api/v1/domains/{id}`

Получить полную информацию о зарегистрированном домене. Поле `nameservers` присутствует только если `cloudflare_enabled: false`.

**curl**
```bash
curl https://app.piv.day/api/v1/domains/dom-uuid-... \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "domain": {
      "id": "dom-uuid-...",
      "domain_name": "mysite.com",
      "status": "active",
      "registered_at": "2026-01-01T12:00:00Z",
      "expires_at": "2027-01-01T12:00:00Z",
      "auto_renew": true,
      "cloudflare_enabled": true,
      "cloudflare_status": "active",
      "ssl_type": "lets_encrypt",
      "ssl_status": "active",
      "ssl_mode": "full",
      "ssl_expires_at": "2026-04-01T00:00:00Z",
      "created_at": "2026-01-01T00:00:00Z",
      "updated_at": "2026-01-01T12:00:00Z",
      "dns_records": [
        { "name": "@", "type": "A", "content": "1.2.3.4", "ttl": 1, "priority": null, "proxied": true },
        { "name": "www", "type": "CNAME", "content": "mysite.com", "ttl": 1, "priority": null, "proxied": true }
      ]
    }
  }
}
```

### Продлить домен

`POST /api/v1/domains/{id}/renew`

Продлить регистрацию домена. Возвращает `queue_id` для отслеживания.

**Тело запроса**

| Поле | Тип | Описание |
| --- | --- | --- |
| `period` * | integer | На сколько лет продлить. |

**curl**
```bash
curl -X POST https://app.piv.day/api/v1/domains/dom-uuid-.../renew \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "period": 1 }'
```

**202 Accepted**
```json
{
  "success": true,
  "data": {
    "queue_id": "que-uuid-...",
    "domain_id": "dom-uuid-...",
    "expires_at": "2027-01-01T12:00:00Z"
  }
}
```

### Авто-продление

`POST /api/v1/domains/{id}/auto-renew`

Включить или отключить автоматическое продление домена.

**Тело запроса**

| Поле | Тип | Описание |
| --- | --- | --- |
| `auto_renew` * | boolean | Новое значение флага. |

**curl**
```bash
curl -X POST https://app.piv.day/api/v1/domains/dom-uuid-.../auto-renew \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "auto_renew": true }'
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "id": "dom-uuid-...",
    "auto_renew": true
  }
}
```

### DNS-записи домена

`GET /api/v1/domains/{id}/dns`

Список DNS-записей домена (через Cloudflare).

**curl**
```bash
curl https://app.piv.day/api/v1/domains/dom-uuid-.../dns \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "records": [
      {
        "id": "rec-uuid-...",
        "type": "A",
        "name": "@",
        "content": "1.2.3.4",
        "ttl": 1,
        "priority": null,
        "proxied": true
      }
    ]
  }
}
```

### Добавить DNS-запись

`POST /api/v1/domains/{id}/dns`

Создать новую DNS-запись.

**Тело запроса**

| Поле | Тип | Описание |
| --- | --- | --- |
| `type` * | string | Тип записи: `A`, `AAAA`, `CNAME`, `MX`, `TXT` и др. |
| `name` * | string | Имя записи, например `@` или `subdomain`. |
| `content` * | string | Значение записи. |
| `ttl` | integer | TTL в секундах (`1` = авто). |
| `proxied` | boolean | Проксировать через Cloudflare. |

**curl**
```bash
curl -X POST https://app.piv.day/api/v1/domains/dom-uuid-.../dns \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "A",
    "name": "@",
    "content": "1.2.3.4",
    "ttl": 1,
    "proxied": true
  }'
```

**201 Created**
```json
{
  "success": true,
  "data": {
    "record": {
      "id": "rec-uuid-...",
      "type": "A",
      "name": "@",
      "content": "1.2.3.4",
      "ttl": 1,
      "priority": null,
      "proxied": true
    }
  }
}
```

### Изменить DNS-запись

`PUT /api/v1/domains/{id}/dns/{recordId}`

Обновить существующую DNS-запись по ID. Перезаписываются только переданные поля.

**curl**
```bash
curl -X PUT https://app.piv.day/api/v1/domains/dom-uuid-.../dns/rec-uuid-... \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "content": "5.6.7.8" }'
```

### Удалить DNS-запись

`DELETE /api/v1/domains/{id}/dns/{recordId}`

Удалить DNS-запись по ID.

**curl**
```bash
curl -X DELETE https://app.piv.day/api/v1/domains/dom-uuid-.../dns/rec-uuid-... \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### Включить Cloudflare

`POST /api/v1/domains/{id}/cloudflare`

Включить Cloudflare для домена. NS-серверы Cloudflare не отдаём — делегирование настраиваем на своей стороне сами. Отключение Cloudflare через этот эндпоинт не поддерживается.

**curl**
```bash
curl -X POST https://app.piv.day/api/v1/domains/dom-uuid-.../cloudflare \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": true }'
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "domain_id": "dom-uuid-...",
    "ssl_mode": "flexible"
  }
}
```

### Сменить NS-серверы

`POST /api/v1/domains/{id}/ns-servers`

Задать произвольные NS-серверы для домена.

**curl**
```bash
curl -X POST https://app.piv.day/api/v1/domains/dom-uuid-.../ns-servers \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "nameservers": ["ns1.example.com", "ns2.example.com"] }'
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "nameservers": [
      { "nameserver": "ns1.example.com", "order_index": 1 },
      { "nameserver": "ns2.example.com", "order_index": 2 }
    ]
  }
}
```

## Вайты

Генерация белых страниц по нише и тиру. Каждый сайт уникален. Смена домена и контактов — без перегенерации.

### Список тиров

`GET /api/v1/whites/tiers`

Список доступных тарифов генерации с ценами. `price` — цена за генерацию уже под ваш аккаунт (с учётом подписки), одна цифра. Качество `quality: "premium"` стоит дороже (считается при создании). Блог только у `v2_tier3`: первые 3 статьи включены, за каждую дополнительную (до 20) — `extra_article_price`.

**curl**
```bash
curl https://app.piv.day/api/v1/whites/tiers \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "tiers": [
      {
        "tier_key": "v2_tier1",
        "name": "Landing",
        "generator_version": "v2",
        "min_articles": 0,
        "max_articles": 0,
        "price": 3.00,
        "extra_article_price": null
      },
      {
        "tier_key": "v2_tier2",
        "name": "Multi-page",
        "generator_version": "v2",
        "min_articles": 0,
        "max_articles": 0,
        "price": 6.00,
        "extra_article_price": null
      },
      {
        "tier_key": "v2_tier3",
        "name": "Full + Blog",
        "generator_version": "v2",
        "min_articles": 3,
        "max_articles": 20,
        "price": 10.00,
        "extra_article_price": 1.50
      }
    ]
  }
}
```

### Список вайтов

`GET /api/v1/whites`

Список ваших задач генерации с возможностью фильтрации.

**Query-параметры**

| Поле | Тип | Описание |
| --- | --- | --- |
| `limit` | integer | Количество записей. По умолчанию: 100, максимум: 500. |
| `offset` | integer | Смещение для пагинации. |
| `status` | string | `queued` \| `processing` \| `done` \| `failed`. |
| `tier_key` | string | `v2_tier1` \| `v2_tier2` \| `v2_tier3`. |

**curl**
```bash
curl "https://app.piv.day/api/v1/whites?status=done&limit=20" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "whites": [
      {
        "id": "job-uuid-...",
        "name": "My White",
        "status": 10,
        "tier_key": "v2_tier3",
        "quality": "standard",
        "niche": "IT Consulting",
        "country": "DE",
        "language": "de",
        "domain": "mysite.com",
        "result_url": null,
        "created_at": "2026-01-01T00:00:00Z"
      }
    ],
    "pagination": { "total": 1, "limit": 20, "offset": 0 }
  }
}
```

### Запустить генерацию

`POST /api/v1/whites`

Поставить задачу генерации вайт-страницы в очередь. Оплата снимается сразу. Финальный статус приходит на вебхук `white.completed` / `white.failed` или проверяется через `GET /whites/{id}`.

**Тело запроса**

| Поле | Тип | Описание |
| --- | --- | --- |
| `name` * | string | Название задания (2–20 символов). |
| `tier_key` * | string | `v2_tier1` \| `v2_tier2` \| `v2_tier3`. |
| `niche` * | string | Тематика сайта (до 25 символов). |
| `country` * | string | Код страны (ISO 3166-1 alpha-2). |
| `language` * | string | Основной язык сайта (ISO 639-1). |
| `quality` | string | `standard` \| `premium` (по умолчанию `standard`). |
| `languages` | string[] | Список языков. Первый включён в цену, каждый следующий — доплата. |
| `domain` | string | Полный домен (напр. `example.com`). Без автоподстановки. |
| `email` | string | Полный email (напр. `info@example.com`). Без автоподстановки. |
| `phone` | string | Телефон контакта. |
| `address` | string | Адрес компании. |
| `legal_name` | string | Юридическое название. |
| `style_hint` | string | Стиль дизайна (Random, Минималистичный, Корпоративный и др.). |
| `keywords` | string[] | Ключевые слова для SEO. |
| `banned_words` | string[] | Слова, запрещённые в контенте. |
| `blog_count` | integer | Кол-во статей блога 3–20. Только для `v2_tier3`. За статьи сверх 3 — доплата. |
| `contacts_mode` | string | `same` \| `template`. |
| `contacts_template` | string | Шаблон контактной страницы (при `contacts_mode=template`). |
| `facebook` | string | Полный URL страницы Facebook. |
| `instagram` | string | Полный URL профиля Instagram. |
| `linkedin` | string | Полный URL профиля LinkedIn. |
| `youtube` | string | Полный URL канала YouTube. |
| `tiktok` | string | Полный URL профиля TikTok. |

**Ошибки**

| Код | HTTP | Когда срабатывает |
| --- | --- | --- |
| `INSUFFICIENT_BALANCE` | 402 | Не хватает средств. |
| `INVALID_TIER` | 400 | Тариф с таким ключом не найден. |
| `VALIDATION_ERROR` | 400 | Некорректное тело запроса. |

**curl**
```bash
curl -X POST https://app.piv.day/api/v1/whites \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Tech Blog DE",
    "tier_key": "v2_tier3",
    "niche": "IT Consulting",
    "country": "DE",
    "language": "de",
    "quality": "premium",
    "languages": ["de", "en"],
    "domain": "techblog-de.com",
    "email": "info@techblog-de.com",
    "phone": "+49 30 123456",
    "address": "Berliner Str. 1, 10115 Berlin",
    "legal_name": "TechBlog GmbH",
    "style_hint": "Корпоративный",
    "keywords": ["IT", "consulting", "cloud"],
    "banned_words": ["cheap", "free"],
    "blog_count": 8,
    "contacts_mode": "same",
    "facebook": "https://facebook.com/techblogde",
    "instagram": "https://instagram.com/techblogde",
    "linkedin": "https://linkedin.com/company/techblogde"
  }'
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "status": "queued",
    "white": {
      "id": "job-uuid-...",
      "name": "Tech Blog DE",
      "status": 0,
      "tier_key": "v2_tier3",
      "quality": "premium",
      "niche": "IT Consulting",
      "country": "DE",
      "language": "de",
      "domain": "techblog-de.com",
      "result_url": null,
      "created_at": "2026-01-01T00:00:00Z"
    }
  }
}
```

### Один вайт

`GET /api/v1/whites/{id}`

Получить текущее состояние задачи генерации.

**curl**
```bash
curl https://app.piv.day/api/v1/whites/job-uuid-... \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "white": {
      "id": "job-uuid-...",
      "name": "Tech Blog DE",
      "status": 10,
      "tier_key": "v2_tier3",
      "quality": "premium",
      "niche": "IT Consulting",
      "country": "DE",
      "language": "de",
      "domain": "techblog-de.com",
      "result_url": null,
      "created_at": "2026-01-01T00:00:00Z"
    }
  }
}
```

### Скачать архив

`GET /api/v1/whites/{id}/download`

Получить подписанную короткоживущую ссылку на готовый архив вайт-страницы. Ссылка действует ~5 минут (см. `expires_at`). Если истекла — просто запроси `/download` ещё раз, выдадим новую. Если вайт ещё не сгенерирован, вернётся `409 NOT_READY`.

**Query-параметры**

| Поле | Тип | Описание |
| --- | --- | --- |
| `format` | string | Формат архива. По умолчанию `php`. |

**Ошибки**

| Код | HTTP | Когда срабатывает |
| --- | --- | --- |
| `NOT_READY` | 409 | Вайт ещё генерируется — повтори запрос после `white.completed`. |

**curl**
```bash
curl "https://app.piv.day/api/v1/whites/job-uuid-.../download?format=php" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**200 OK**
```json
{
  "success": true,
  "data": {
    "url": "https://strg.piv.day/download/<user_id>/<job_id>?format=php&token=<hmac>&filename=<name>.zip",
    "filename": "example.com_2026-05-28_DE_en.zip",
    "format": "php",
    "expires_at": "2026-05-28T14:46:00Z"
  }
}
```

### Сменить домен и контакты

`POST /api/v1/whites/{id}/config`

Обновить контактные данные компании в вайт-странице без повторной генерации.

**curl**
```bash
curl -X POST https://app.piv.day/api/v1/whites/job-uuid-.../config \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "company": "My Brand",
    "domain": "newdomain.com",
    "email": "info@newdomain.com",
    "phone": "+49 30 123456",
    "address": "Berliner Str. 1, Berlin",
    "legal": "My Brand GmbH"
  }'
```

## Вебхуки

На ваш URL отправляется обычный POST с JSON-телом. Формат одинаковый для всех событий: `event_type`, `timestamp` и блок `data`. Ваш сервер должен ответить любым 2xx за 5 секунд.

```
POST <your webhook URL>
Content-Type: application/json
User-Agent: piv.day-webhook/1.0

{
  "event_type": "<event identifier>",
  "timestamp": "2026-05-22T12:34:56Z",
  "data": { ... }
}
```

**Повторы.** При не-2xx или таймауте — до 3 повторов с задержкой 1 с, 2 с, 4 с. История всех попыток доступна на странице API-ключей в дашборде. Если все три не прошли — событие отмечается как failed, можно переотправить вручную.

**Безопасность.** Используйте HTTPS-эндпойнт. Каждый запрос приходит с заголовком `User-Agent: piv.day-webhook/1.0`. URL для вебхуков настраивается в профиле API-ключа.

### Все события

| Событие | Когда срабатывает |
| --- | --- |
| `sms.received` | На ваш номер пришло SMS от доверенного отправителя. |
| `sms.status_updated` | Исходящее SMS поменяло статус — например, ушло в доставку или провалилось. |
| `number.restore_completed` | Пакетный Restore доехал до конца — приходит финальный итог. |
| `verify.completed` | Верификация Google-аккаунта закрылась успешно. |
| `verify.failed` | Что-то пошло не так — Google не пропустил. |
| `proxy.expires_soon` | До конца аренды заказа прокси осталось около трёх дней. |
| `domain.registered` | Заказ на регистрацию закрылся успешно — домен живой. |
| `domain.failed` | Заказ не дошёл до конца — частая причина: домен только что заняли. |
| `domain.expires_soon` | До истечения домена осталось около недели. |
| `white.completed` | Задача генерации вайта закрылась успешно. |
| `white.failed` | Задача упала — деньги возвращаются на баланс. |

### Входящее SMS на ваш номер

**`sms.received`**

Самое частое — коды подтверждения от рекламных сетей. В payload приходит и сырой текст, и автоматически распознанный код (если есть) — можно сразу пробросить в свой воркфлоу без парсинга. SMS от заведомо спамных отправителей через вебхук не присылаются.

```json
{
  "event_type": "sms.received",
  "timestamp": "2026-05-22T12:34:56Z",
  "data": {
    "piv_num_id": "vzPA1-kHKSg-EAL7e-Jqd3o",
    "text": "Your verification code is 123456",
    "code": "123456",
    "country": "SE",
    "received_at": "2026-05-22T12:34:56Z"
  }
}
```

### Статус отправленного SMS изменился

**`sms.status_updated`**

Подходит, если вы шлёте подтверждения от своего имени и хотите знать, что сообщение реально дошло. Если статус failed — в payload приходят код и текст ошибки от оператора.

```json
{
  "event_type": "sms.status_updated",
  "timestamp": "2026-05-22T12:34:56Z",
  "data": {
    "piv_num_id": "vzPA1-kHKSg-EAL7e-Jqd3o",
    "message_id": "42",
    "old_status": "sent",
    "new_status": "delivered",
    "error_code": null,
    "error_message": null
  }
}
```

### Восстановление номеров завершено

**`number.restore_completed`**

Содержит два списка: какие номера вернулись и какие нет. За не вернувшиеся номера сумма возвращается на баланс — она тоже в payload. Удобно для скриптов: понятно, что просить заново.

```json
{
  "event_type": "number.restore_completed",
  "timestamp": "2026-05-22T12:34:56Z",
  "data": {
    "restored": [
      {
        "piv_num_id": "vzPA1-kHKSg-EAL7e-Jqd3o",
        "phone_number": "+46764794425",
        "country": "SE"
      }
    ],
    "failed": [
      {
        "piv_num_id": "abc12-defgh-ijklm-nopqr",
        "phone_number": "+46123456789",
        "country": "SE",
        "refunded": 7.50
      }
    ],
    "total_restored": 1,
    "total_failed": 1,
    "total_refunded": 7.50
  }
}
```

### Google QR-верификация прошла

**`verify.completed`**

Если в процессе пришло SMS с кодом — оно уже здесь, не нужно отдельно его забирать. Поля captured_phone и captured_message содержат то, что отправил Google.

```json
{
  "event_type": "verify.completed",
  "timestamp": "2026-05-22T12:34:56Z",
  "data": {
    "task_id": 12,
    "piv_num_id": "vzPA1-kHKSg-EAL7e-Jqd3o",
    "status": "sms_sent",
    "captured_phone": "+14155551234",
    "captured_message": "Your Google verification code is 123456",
    "sms_message_id": 42,
    "sms_status": "queued"
  }
}
```

### Google QR-верификация не прошла

**`verify.failed`**

Поле error_code говорит, что именно: таймаут, отказ, невалидный URL. Сумма за неуспешную верификацию возвращается на баланс автоматически.

```json
{
  "event_type": "verify.failed",
  "timestamp": "2026-05-22T12:34:56Z",
  "data": {
    "task_id": 12,
    "piv_num_id": "vzPA1-kHKSg-EAL7e-Jqd3o",
    "status": "failed",
    "error_code": "VERIFY_TIMEOUT",
    "error_message": "Verification timed out"
  }
}
```

### Прокси скоро истекут

**`proxy.expires_soon`**

Нужно для тех, кто продлевает не автоматически: успеваете заранее увидеть и решить — продлить или закрыть кампанию. Если хочется, можно подписаться и сразу дёргать POST /proxy/orders/{id}/renew.

```json
{
  "event_type": "proxy.expires_soon",
  "timestamp": "2026-05-22T12:34:56Z",
  "data": {
    "order_id": "ord-uuid-...",
    "country": "DE",
    "quantity": 10,
    "expires_at": "2026-05-25T00:00:00Z"
  }
}
```

### Домен зарегистрирован

**`domain.registered`**

Если при покупке вы запросили Cloudflare и SSL, всё уже поднято — флаг cloudflare_enabled покажет статус. Можно сразу добавлять DNS-записи или раскатывать сайт.

```json
{
  "event_type": "domain.registered",
  "timestamp": "2026-05-22T12:34:56Z",
  "data": {
    "domain_id": "dom-uuid-...",
    "domain_name": "mysite.com",
    "registered_at": "2026-05-22T12:34:56Z",
    "expires_at": "2027-05-22T12:34:56Z",
    "cloudflare_enabled": true
  }
}
```

### Регистрация домена не удалась

**`domain.failed`**

Поле error содержит человекочитаемое объяснение. Сумма возвращается на баланс. Можно перевыбрать другое имя и оформить заказ заново.

```json
{
  "event_type": "domain.failed",
  "timestamp": "2026-05-22T12:34:56Z",
  "data": {
    "domain_id": "dom-uuid-...",
    "domain_name": "mysite.com",
    "error": "Domain is no longer available"
  }
}
```

### Домен скоро истечёт

**`domain.expires_soon`**

Удобно, если авто-продление выключено: успеваете продлить вручную до того, как домен уйдёт в редемпшен. Флаг auto_renew подскажет, нужно ли вмешиваться.

```json
{
  "event_type": "domain.expires_soon",
  "timestamp": "2026-05-22T12:34:56Z",
  "data": {
    "domain_id": "dom-uuid-...",
    "domain_name": "mysite.com",
    "expires_at": "2026-05-29T00:00:00Z",
    "auto_renew": false
  }
}
```

### Вайт сгенерирован

**`white.completed`**

Архив доступен через GET /whites/{id}/download. Если у вайта был указан домен, sitemap и контакты уже подставлены под него — можно сразу деплоить.

```json
{
  "event_type": "white.completed",
  "timestamp": "2026-05-22T12:34:56Z",
  "data": {
    "job_id": "job-uuid-...",
    "name": "My White",
    "tier_key": "t1",
    "country": "DE"
  }
}
```

### Генерация вайта не удалась

**`white.failed`**

Поле error объясняет причину. Можно сразу запустить новую задачу через POST /whites — без потерь.

```json
{
  "event_type": "white.failed",
  "timestamp": "2026-05-22T12:34:56Z",
  "data": {
    "job_id": "job-uuid-...",
    "name": "My White",
    "error": "Generation failed"
  }
}
```

## Коды ошибок

Все ошибки возвращаются в одном формате: HTTP-статус + поле `error.code` + человеческое сообщение в `error.message`.

```json
{
  "success": false,
  "error": {
    "code": "INSUFFICIENT_BALANCE",
    "message": "Not enough balance: required $5.00, available $1.20"
  }
}
```

| Код | HTTP | Когда срабатывает |
| --- | --- | --- |
| `UNAUTHORIZED` | 401 | Ключ отсутствует, истёк или отозван. |
| `INSUFFICIENT_PERMISSIONS` | 403 | У ключа нет нужного скоупа для этого действия. |
| `PERMISSION_DENIED` | 403 | Аккаунт-уровень доступа не позволяет действие (например выкл. функция). |
| `VALIDATION_ERROR` | 400 | Невалидное тело запроса. Сообщение объясняет, какое поле и почему. |
| `NUMBER_NOT_FOUND` | 404 | Номер не существует или не принадлежит аккаунту. |
| `NUMBER_EXPIRED` | 403 | Номер истёк — нужно Restore (в 7-дневное окно) или новая покупка. |
| `NUMBER_NOT_ACTIVE` | 400 | Номер в статусе, не разрешающем эту операцию. |
| `INSUFFICIENT_BALANCE` | 402 | Не хватает средств для операции. |
| `INVALID_MESSAGE_FORMAT` | 400 | Тело SMS слишком длинное или содержит запрещённые символы. |
| `COUNTRY_NOT_AVAILABLE` | 400 | Страна недоступна для покупки или продления. |
| `NO_NUMBERS_AVAILABLE` | 400 | В выбранной стране сейчас нет свободных номеров. |
| `NO_RESTORABLE_NUMBERS` | 404 | Все переданные номера уже невозможно восстановить. |
| `RATE_LIMITED` | 429 | Превышен rate limit. Ждите время из заголовка `Retry-After`. |
| `INTERNAL_ERROR` | 500 | Что-то пошло не так у нас. Если повторяется — пишите в саппорт. |
