Email API
Документация (RU) ▼
Два продукта под одним API: разовые активации (получение кода на временный email) и аренда почтового ящика (постоянный email на срок с доступом ко всем письмам). У них разные форматы ответа — это сделано намеренно, чтобы клиенты, уже интегрированные с апстримами, могли переключиться сменой хоста и ключа без переписывания парсеров:
- Контракт 1 (активации) — конверт
{data: ...}, формат, привычный по массовым сервисам email-активаций. - Контракт 2 (аренда) — конверт
{success, result}, формат мультисайт-аренды почтового ящика.
Аутентификация
Основной способ — заголовок Authorization: ApiKey <ваш ключ>. Префикс ApiKey обязателен: без него запрос будет отклонён как неавторизованный.
Также поддерживаются (fallback, для совместимости с остальными нашими API):
X-Api-Key: <ключ>Authorization: Bearer <ключ>- Ключ передаётся ТОЛЬКО заголовком. Параметр
?key=в этом API не принимается: денежные методы контракта аренды ходят по GET, и ключ из query-строки осел бы в access-логах сервера, ротациях и бэкапах.
Ключ никогда не передаётся в пути URL — ни один маршрут этого API его так не принимает.
Где взять ключ: тот же API‑ключ, что и для OTP/Numbers/Proxy API — раздел API в личном кабинете.
Лимиты: чтение — 60 запросов/мин на ключ; мутации (покупка/отмена/reorder/reuse/batch, а также заказ/продление аренды) — 20 запросов/мин на ключ. Счётчики раздельные: активации, аренда, котировка аренды и история транзакций считаются независимо.
Идемпотентность мутаций
Сетевой таймаут на запросе к нам не должен стоить вам второго списания. Любая мутация принимает ключ идемпотентности — параметром idempotency_key либо заголовком Idempotency-Key (до 128 символов):
- покупка активаций —
POST /api/v1/emails,POST /api/v1/emails/{id}/reorder,POST /api/v1/emails/{id}/reuse,POST /api/v1/emails/batch; - аренда —
multisiteOrder,multisiteExtend,multisiteReorder.
Повтор с тем же ключом возвращает первый ответ — то же тело и тот же HTTP‑статус, плюс заголовок Idempotent-Replay: true. Ничего не покупается и не списывается второй раз.
Правила:
- ключ живёт 24 часа и действует в границах одного метода: один и тот же ключ на
multisiteOrderиmultisiteExtend— две разные операции, а не повтор; - ключи изолированы по API‑ключу: чужой
idempotency_keyникогда не отдаст чужой ответ; - если первый запрос ещё выполняется —
409(IDEMPOTENCY_IN_PROGRESSв контракте 1), повторите через секунду; - сохраняется только успех. Если запрос завершился отказом (не хватило баланса, цена выше
max_cost, нет ящиков), ключ освобождается — законный повтор после пополнения баланса пройдёт; - без ключа поведение прежнее: каждый запрос — отдельная покупка.
Генерируйте ключ на своей стороне (UUID на каждую пользовательскую операцию) и переиспользуйте его при ретраях — именно так он и защищает.
Контракт 1 — Разовые активации
Базовый URL: https://sms-acktiwator.ru/api/v1/emails
Успех: {"data": Activation} или {"data": [Activation, ...], "meta": {...}}. Ошибка: {"error": "...", "code": "..."} с соответствующим HTTP‑статусом.
site — ЛЮБОЙ целевой сайт (свободная строка, например telegram.org или домен со ссылкой — нормализуется автоматически). domain — домен почтового ящика (например gmail.com), берётся из каталога GET .../domains.
Форма Activation:
| Поле | Тип | Описание |
|---|---|---|
id | int | ID активации |
site | string | Целевой сайт (как передан при покупке, нормализован) |
email | string|null | Арендованный email‑адрес |
status | string | WAIT / DONE / CANCEL / TIMEOUT |
value | string|null | Код/значение из письма; null, пока не пришло |
cost | string | Списанная с вас цена |
currency | string | Всегда "USD" |
date | string | ISO‑8601 UTC, дата создания активации |
message | string|null | Зарезервировано (сейчас всегда null) |
Статусы: WAIT — ожидание кода; DONE — код получен; CANCEL — активация отменена (средства возвращены); TIMEOUT — истекло время ожидания.
1) GET /api/v1/emails — список активаций
| Параметр | Тип | Обязателен | Описание |
|---|---|---|---|
search | string | нет | Поиск по site/email/domain |
size | int | нет | Размер страницы, ≤100 (по умолчанию 25) |
page | int | нет | Номер страницы (по умолчанию 1) |
status | string | нет | WAIT/DONE/CANCEL/TIMEOUT |
from | string | нет | ISO‑дата/время — нижняя граница date |
to | string | нет | ISO‑дата/время — верхняя граница date |
Запрос:
GET https://sms-acktiwator.ru/api/v1/emails?status=WAIT&size=25&page=1
Authorization: ApiKey YOUR_API_KEY
Ответ (200):
{
"data": [ { "id": 12345, "site": "telegram.org", "email": "z@gmail.com",
"status": "WAIT", "value": null, "cost": "0.10",
"currency": "USD", "date": "2026-07-31T10:00:00Z", "message": null } ],
"meta": { "page": 1, "size": 25, "total": 1 }
}
2) POST /api/v1/emails — купить активацию
| Параметр | Тип | Обязателен | Описание |
|---|---|---|---|
site | string | да | Целевой сайт (любой) |
domain | string | да | Домен почтового ящика |
Запрос:
POST https://sms-acktiwator.ru/api/v1/emails
Authorization: ApiKey YOUR_API_KEY
Content-Type: application/x-www-form-urlencoded
site=telegram.org&domain=gmail.com
Ответ (201): {"data": Activation} с status="WAIT" и value=null.
Ошибки: 422 BAD_PARAMS — не заданы site/domain; 409 NO_OFFER — нет доступных ящиков по направлению (либо не хватает баланса).
3) GET /api/v1/emails/{id} — получить активацию (проверить код)
Запрос:
GET https://sms-acktiwator.ru/api/v1/emails/12345
Authorization: ApiKey YOUR_API_KEY
Ответ (200): {"data": Activation}. Поллите этот метод до терминального статуса (DONE/CANCEL/TIMEOUT).
Ошибки: 404 NOT_FOUND — активация не найдена или принадлежит другому пользователю.
4) DELETE /api/v1/emails/{id} — отменить активацию
Запрос:
DELETE https://sms-acktiwator.ru/api/v1/emails/12345
Authorization: ApiKey YOUR_API_KEY
Ответ: 204 без тела. Отменяет активацию и возвращает списанные средства на баланс.
Ошибки: 404 NOT_FOUND — чужая/не найдена; 409 CANNOT_CANCEL — активация уже закрыта (завершена/отменена/истекла).
5) POST /api/v1/emails/{id}/reorder — купить ещё раз (тот же site/domain)
Запрос:
POST https://sms-acktiwator.ru/api/v1/emails/12345/reorder
Authorization: ApiKey YOUR_API_KEY
Ответ (201): {"data": Activation} — новая активация с теми же site/domain, что у исходной (её собственный статус не важен и не меняется).
Ошибки: 404 NOT_FOUND — исходная активация чужая/не найдена; 409 NO_OFFER — нет доступных ящиков.
6) POST /api/v1/emails/{id}/reuse — ещё одно письмо на ТОТ ЖЕ адрес
Запрос:
POST https://sms-acktiwator.ru/api/v1/emails/12345/reuse
Authorization: ApiKey YOUR_API_KEY
Не путать с reorder: reorder покупает ДРУГОЙ ящик, а reuse оставляет прежний адрес — сайты, которые второй адрес уже не примут, требуют именно этого.
Когда доступен: первый код по активации уже получен и с этого момента прошло не больше 20 минут (reuse_until в карточке активации), не больше 3 повторов на активацию, и поставщик этой активации повтор поддерживает. Все четыре условия видны заранее в полях reuse_until/reuse_left метода GET /api/v1/emails/{id}: reuse_until: null значит, что повтора по этой активации не будет.
Ответ (200): {"data": Activation} — та же активация (тот же id и email), снова в статусе WAIT. Поле value продолжает держать ПРЕДЫДУЩИЙ код, пока не придёт новое письмо: по смене value и определяется, что второе письмо дошло.
Цена: повтор тарифицируется как обычная активация по тому же направлению, если за него берёт деньги поставщик, и бесплатен, если не берёт. Если второе письмо так и не пришло до конца окна, доплата за повтор возвращается автоматически; исходная цена активации не возвращается — первый код вы уже получили.
Ошибки: 404 NOT_FOUND — активация чужая/не найдена; 409 CANNOT_REUSE — окно закрыто, лимит выбран, кода ещё не было или поставщик повтор не поддерживает; 429 CHANNEL_LIMIT — предыдущий повтор по этой активации ещё выполняется.
Принимает idempotency_key (см. ниже): повтор запроса с тем же ключом отдаёт прежний результат и не тратит вторую попытку.
7) POST /api/v1/emails/batch — купить несколько активаций подряд
| Параметр | Тип | Обязателен | Описание |
|---|---|---|---|
count | int | да | 1..10 |
site | string | да | Целевой сайт (общий для всей пачки) |
domain | string | да | Домен (общий для всей пачки) |
Ответ (201): {"data": [Activation, ...], "meta": {"info": string|null, "count": int}}. При частичном успехе (сток закончился на N‑й покупке) data содержит только купленные, meta.count — их число, meta.info поясняет причину остановки.
Ошибки: 422 BAD_PARAMS — count вне 1..10 или не заданы site/domain.
8) GET /api/v1/emails/domains — каталог доменов и цен
Запрос:
GET https://sms-acktiwator.ru/api/v1/emails/domains
Authorization: ApiKey YOUR_API_KEY
Ответ (200):
{
"data": [
{ "name": "gmail.com", "cost": "0.15", "count": 42 },
{ "name": "outlook.com", "cost": "0.20", "count": 7 }
]
}
| Параметр | Тип | Обязателен | Описание |
|---|---|---|---|
site | string | нет | Целевой сайт, под который считать цены. Без него — сайт по умолчанию |
Параметр ?site= влияет на выдачу. Себестоимость ящика зависит от целевого сайта в разы, поэтому каталог считается именно под переданный сайт. Запрашивайте домены с тем же site, с которым потом будете покупать: цены, снятые под другой сайт, не совпадут с реальными, и на покупке вы получите 409 NO_OFFER по домену, который в каталоге выглядел доступным.
Общее для обоих контрактов
GET /api/v1/transactions — история операций с балансом
Списания, пополнения и возвраты по вашему аккаунту — для сверки расходов. Метод не привязан к продукту и доступен, даже если активации или аренда вам не подключены: это ваши деньги. Конверт — как у контракта 1 ({data, meta}).
| Параметр | Тип | Обязателен | Описание |
|---|---|---|---|
type | string | нет | Фильтр по типу операции (см. поле type в ответе). Неизвестный тип — пустая выдача, не ошибка |
from | string | нет | С какой даты/времени (ISO‑8601 или YYYY-MM-DD) |
to | string | нет | По какую дату/время |
page | int | нет | Страница, с 1 |
size | int | нет | Размер страницы, 1..100 (по умолчанию 25) |
Запрос:
GET https://sms-acktiwator.ru/api/v1/transactions?from=2026-09-01&size=50
Authorization: ApiKey YOUR_API_KEY
Ответ (200):
{
"data": [
{ "id": 987654, "type": "email_rent_payment", "direction": "out",
"amount": "0.0421", "currency": "USD",
"balance_before": "5.0000", "balance_after": "4.9579",
"description": "Аренда email #1000042 · abc123@zickmail.com · 2 сайтов · 24 ч · Qeex",
"date": "2026-09-02T10:05:00Z" }
],
"meta": { "page": 1, "size": 50, "total": 1 }
}
amount всегда положительный — направление денег несёт поле direction: "in" (пополнение, возврат) или "out" (списание). Не выводите знак из type: список типов пополняется, и захардкоженный маппинг однажды молча соврёт.
Записи отсортированы от новых к старым. transaction_id из ответов аренды — это id отсюда.
Контракт 2 — Аренда почтового ящика (мультисайт)
Базовый URL: https://sms-acktiwator.ru/api/v1/ + название метода. Методы принимают и GET, и POST (GET — для совместимости с привычным форматом, POST — более корректный способ для операций, меняющих состояние).
Успех: {"success": true, "result": ...}. Ошибка: {"success": false, "error": "..."} с соответствующим HTTP‑статусом (без поля code).
Важно для интеграторов — особенности нашей реализации:
- минимальный срок аренды — 12 часов (максимум — 1440 часов = 60 дней);
- отмены аренды нет — аренда невозвратна;
- письма отдаются из нашей базы (крон синкает их с провайдером примерно раз в 2 минуты), поэтому они доступны и после окончания срока аренды.
multisiteOffers — котировка аренды
Цены аренды по доменам для конкретного набора. Тариф линеен по числу сайтов и по часам, поэтому «цены за домен» в отрыве от набора не существует: спрашивайте котировку ровно с тем period и sites, с которыми будете заказывать.
| Параметр | Тип | Обязателен | Описание |
|---|---|---|---|
period | int | нет | Срок в часах, 12..1440 (по умолчанию 12) |
sites | int | нет | Количество сайтов, 1..50 (по умолчанию 1) |
Запрос:
GET https://sms-acktiwator.ru/api/v1/multisiteOffers?period=24&sites=2
Authorization: ApiKey YOUR_API_KEY
Ответ (200):
{ "success": true, "result": [
{ "domain": "zickmail.com", "cost": "0.0421", "currency": "USD", "count": 12 }
] }
count — сколько ящиков домена доступно. Цена детерминирована по тройке (домен, число сайтов, часы) и не резервируется: сама по себе она не «плавает», а от изменения тарифа между вашими двумя запросами защищает параметр max_cost в multisiteOrder.
Ошибки: 422 — period вне 12..1440, sites вне 1..50 либо нечисловое значение. Значения вне диапазона не подгоняются к границе: мы не пересчитываем ваш запрос в другую цену молча.
multisiteOrder — заказать аренду ящика
| Параметр | Тип | Обязателен | Описание |
|---|---|---|---|
domain | string | да | Домен ящика |
sites | string | да | Список целевых сайтов через запятую |
period | int | да | Срок в часах, 12..1440 |
max_cost | string | нет | Потолок цены в USD. Если аренда стоит дороже — 422 без списания |
idempotency_key | string | нет | Ключ идемпотентности (см. раздел выше) |
Запрос:
POST https://sms-acktiwator.ru/api/v1/multisiteOrder
Authorization: ApiKey YOUR_API_KEY
Content-Type: application/x-www-form-urlencoded
domain=zickmail.com&sites=instagram.com,discord.com&period=12
Ответ (201):
{ "success": true, "result": {
"id": 1000042, "email": "abc123@zickmail.com", "expire": 43200,
"cost": "0.0421", "currency": "USD",
"transaction_id": 987654, "balance_before": "5.0000", "balance_after": "4.9579"
} }
expire — секунды до истечения аренды. cost — сколько списано, строкой (не числом с плавающей точкой: на длинном сроке через float терялись бы копейки). transaction_id, balance_before и balance_after — та же операция в вашей истории GET /api/v1/transactions, по ним удобно сводить расходы.
Ошибки: 422 — не заданы domain/sites, period вне 12..1440 ("Период аренды: 12..1440 часов"), некорректный max_cost либо цена выше max_cost ("Цена выше переданного потолка max_cost", деньги не тронуты); 409 — бизнес‑отказ (нет доступных ящиков по домену, не хватает баланса).
multisiteInfo — статус аренды
Запрос: GET .../api/v1/multisiteInfo?id=1000042 (+ заголовок авторизации)
Ответ (200):
{ "success": true, "result": { "id": 1000042, "email": "abc123@zickmail.com", "expire": 43180, "expired": false } }
После истечения срока expire становится отрицательным, а expired — true (аренда при этом остаётся в системе, письма продолжают быть доступны).
Ошибки: 404 — аренда чужая или не найдена.
multisiteLetters — письма ящика
Запрос: GET .../api/v1/multisiteLetters?id=1000042
Ответ (200):
{ "success": true, "result": [
{ "from": "noreply@discord.com", "subject": "Verify your email",
"data": "112233", "received_at": "2026-07-31T10:05:00Z" }
] }
Письма отдаются из нашей БД без обращения к провайдеру — доступны и после окончания аренды.
Ошибки: 404 — аренда чужая или не найдена.
multisiteExtend — продлить аренду
| Параметр | Тип | Обязателен | Описание |
|---|---|---|---|
id | int | да | ID аренды |
period | int | да | Доп. срок в часах, 12..1440 |
max_cost | string | нет | Потолок цены доплаты в USD |
idempotency_key | string | нет | Ключ идемпотентности |
Ответ (200):
{ "success": true, "result": {
"ok": true, "cost": "0.0421", "currency": "USD", "expire": 86400,
"transaction_id": 987655, "balance_before": "4.9579", "balance_after": "4.9158"
} }
cost — стоимость этого продления (не суммарная по аренде), expire — секунды до нового срока.
Изменение контракта (сентябрь 2026): раньше метод возвращал result: true|false, и отказ приезжал со статусом 200. Теперь result — объект, а отказ приходит статусом 409 и {"success": false, "error": "..."}. Проверять успех по истинности result больше нельзя: объект истинен всегда — ориентируйтесь на HTTP‑статус или на поле success.
Ошибки: 422 — period вне 12..1440, некорректный max_cost или цена выше него; 404 — аренда чужая/не найдена; 409 — бизнес‑отказ (не хватает баланса, аренда не активна, отказ поставщика — деньги при этом возвращены).
multisiteReorder — новая аренда на тех же domain/sites
Запрос: POST .../api/v1/multisiteReorder с id (исходной аренды) и period. Принимает также max_cost и idempotency_key.
Ответ (201): тот же объект, что у multisiteOrder (включая cost, transaction_id, balance_before/balance_after) — новая аренда на том же домене и с тем же списком сайтов, что у исходной.
Ошибки: 404 — исходная аренда чужая/не найдена; 409/422 — как у multisiteOrder.
Коды ошибок
Контракт 1 (активации), поле code:
| HTTP | code | Когда |
|---|---|---|
| 401 | BAD_KEY | Ключ не передан, не найден или неактивен |
| 403 | BANNED | Аккаунт заблокирован |
| 403 | FORBIDDEN | Продукт (Email‑активации) не подключён аккаунту |
| 404 | NOT_FOUND | Активация не найдена или принадлежит другому пользователю |
| 409 | NO_OFFER | Нет доступных ящиков по site/domain (в т.ч. недостаточно средств) |
| 409 | CANNOT_CANCEL | Активация уже закрыта — отменить нельзя |
| 409 | IDEMPOTENCY_IN_PROGRESS | Запрос с этим idempotency_key ещё выполняется |
| 422 | BAD_PARAMS | Не заданы обязательные параметры, count вне 1..10 либо idempotency_key длиннее 128 символов |
| 429 | CHANNEL_LIMIT | Превышен лимит запросов на ключ |
Контракт 2 (аренда), поле error (без code):
| HTTP | error | Когда |
|---|---|---|
| 401 | «Bad API key» | Ключ не передан, не найден или неактивен |
| 403 | «Account is banned» | Аккаунт заблокирован |
| 403 | «Product disabled» | Продукт (аренда ящиков) не подключён аккаунту |
| 404 | «Rental not found» | Аренда чужая или не найдена |
| 409 | текст причины | Бизнес‑отказ (нет ящиков по домену, не хватает баланса) |
| 422 | «domain and sites required» | Не заданы обязательные параметры |
| 422 | «Период аренды: 12..1440 часов» | period вне допустимого диапазона |
| 422 | «Цена выше переданного потолка max_cost» | Цена превысила max_cost — списания не было |
| 409 | «Request with this idempotency_key is still in progress» | Запрос с этим idempotency_key ещё выполняется |
| 429 | «Rate limit exceeded» | Превышен лимит запросов на ключ |
Примеры
Ключ во всех примерах — плейсхолдер YOUR_API_KEY, замените на свой.
Купить активацию и дождаться кода
curl:
curl -X POST "https://sms-acktiwator.ru/api/v1/emails" \
-H "Authorization: ApiKey YOUR_API_KEY" \
-d "site=telegram.org" -d "domain=gmail.com"
# затем поллинг:
curl "https://sms-acktiwator.ru/api/v1/emails/12345" \
-H "Authorization: ApiKey YOUR_API_KEY"
Python (requests):
import time
import requests
BASE = "https://sms-acktiwator.ru/api/v1"
HEADERS = {"Authorization": "ApiKey YOUR_API_KEY"}
r = requests.post(f"{BASE}/emails", headers=HEADERS,
data={"site": "telegram.org", "domain": "gmail.com"})
r.raise_for_status()
activation = r.json()["data"]
while True:
r = requests.get(f"{BASE}/emails/{activation['id']}", headers=HEADERS)
data = r.json()["data"]
if data["status"] == "DONE":
print("code:", data["value"])
break
if data["status"] in ("CANCEL", "TIMEOUT"):
raise RuntimeError(data["status"])
time.sleep(3)
JavaScript (fetch):
const BASE = "https://sms-acktiwator.ru/api/v1";
const HEADERS = { "Authorization": "ApiKey YOUR_API_KEY" };
async function buyAndWaitCode(site, domain) {
const created = await fetch(`${BASE}/emails`, {
method: "POST",
headers: { ...HEADERS, "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({ site, domain }),
}).then(r => r.json());
const id = created.data.id;
while (true) {
const { data } = await fetch(`${BASE}/emails/${id}`, { headers: HEADERS }).then(r => r.json());
if (data.status === "DONE") return data.value;
if (data.status === "CANCEL" || data.status === "TIMEOUT") throw new Error(data.status);
await new Promise(res => setTimeout(res, 3000));
}
}
Заказать аренду ящика и прочитать письма
curl:
curl -X POST "https://sms-acktiwator.ru/api/v1/multisiteOrder" \
-H "Authorization: ApiKey YOUR_API_KEY" \
-d "domain=zickmail.com" -d "sites=instagram.com,discord.com" -d "period=12"
curl "https://sms-acktiwator.ru/api/v1/multisiteLetters?id=1000042" \
-H "Authorization: ApiKey YOUR_API_KEY"
Python (requests):
r = requests.post(f"{BASE}/multisiteOrder", headers=HEADERS,
data={"domain": "zickmail.com", "sites": "instagram.com,discord.com", "period": 12})
order = r.json()["result"]
r = requests.get(f"{BASE}/multisiteLetters", headers=HEADERS, params={"id": order["id"]})
letters = r.json()["result"]
JavaScript (fetch):
const order = await fetch(`${BASE}/multisiteOrder`, {
method: "POST",
headers: { ...HEADERS, "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({ domain: "zickmail.com", sites: "instagram.com,discord.com", period: 12 }),
}).then(r => r.json());
const letters = await fetch(`${BASE}/multisiteLetters?id=${order.result.id}`, { headers: HEADERS })
.then(r => r.json());
Устаревшее API
⚠️ Эндпоинты /api/email-otp/get/, /api/email-otp/status/, /api/email-otp/cancel/ — устаревшие (deprecated), оставлены только ради уже работающих интеграций. Для новых интеграций используйте исключительно /api/v1/emails* (контракт 1 выше).
Documentation (EN) ▼
Two products under one API: one‑off activations (receive a code on a temporary email) and mailbox rental (a persistent email for a period with access to all letters). They use different response envelopes on purpose — this lets clients already integrated with the upstream providers switch by changing the host and key only, with no parser rewrites:
- Contract 1 (activations) —
{data: ...}envelope, the format commonly used by email-activation services. - Contract 2 (rental) —
{success, result}envelope, the multisite mailbox-rental format.
Authentication
Primary method — header Authorization: ApiKey <your key>. The literal ApiKey prefix is required; without it the request is rejected as unauthenticated.
Also supported (fallback, for compatibility with our other APIs):
X-Api-Key: <key>Authorization: Bearer <key>- The key is accepted in headers only. The
?key=query parameter is not supported here: rental-contract money methods accept GET, so a key in the query string would end up in server access logs, rotations and backups.
The key is never accepted in the URL path — no route in this API reads it that way.
Where to get a key: the same API key used for OTP/Numbers/Proxy API — the API section of your account.
Limits: reads — 60 requests/min per key; mutations (buy/cancel/reorder/reuse/batch, and rental order/extend) — 20 requests/min per key. Counters are independent: activations, rentals, rental quotes and transaction history each have their own.
Idempotent mutations
A network timeout on a request to us must not cost you a second charge. Every mutation accepts an idempotency key — as the idempotency_key parameter or the Idempotency-Key header (up to 128 chars):
- activation purchases —
POST /api/v1/emails,POST /api/v1/emails/{id}/reorder,POST /api/v1/emails/{id}/reuse,POST /api/v1/emails/batch; - rentals —
multisiteOrder,multisiteExtend,multisiteReorder.
A repeat with the same key returns the first response — same body, same HTTP status, plus an Idempotent-Replay: true header. Nothing is bought or charged twice.
Rules:
- a key lives for 24 hours and is scoped to a single method: the same key on
multisiteOrderandmultisiteExtendmeans two different operations, not a repeat; - keys are isolated per API key: someone else's
idempotency_keywill never return their response; - if the first request is still running —
409(IDEMPOTENCY_IN_PROGRESSin contract 1), retry in a second; - only success is stored. If the request was declined (insufficient balance, price above
max_cost, no mailboxes), the key is released — a legitimate retry after topping up will go through; - without a key behaviour is unchanged: every request is a separate purchase.
Generate the key on your side (a UUID per user-facing operation) and reuse it across retries — that is exactly how it protects you.
Contract 1 — One-off activations
Base URL: https://sms-acktiwator.ru/api/v1/emails
Success: {"data": Activation} or {"data": [Activation, ...], "meta": {...}}. Error: {"error": "...", "code": "..."} with a matching HTTP status.
site — ANY target site (free-form string, e.g. telegram.org, or a full URL — normalized automatically). domain — the mailbox domain (e.g. gmail.com), taken from the GET .../domains catalog.
Activation shape:
| Field | Type | Description |
|---|---|---|
id | int | Activation ID |
site | string | Target site (as submitted, normalized) |
email | string|null | Rented email address |
status | string | WAIT / DONE / CANCEL / TIMEOUT |
value | string|null | Code/value from the letter; null until received |
cost | string | Amount charged |
currency | string | Always "USD" |
date | string | ISO-8601 UTC, creation date |
message | string|null | Reserved (currently always null) |
Statuses: WAIT — waiting for the code; DONE — code received; CANCEL — cancelled (funds refunded); TIMEOUT — waiting window expired.
1) GET /api/v1/emails — list activations
| Parameter | Type | Required | Description |
|---|---|---|---|
search | string | no | Search over site/email/domain |
size | int | no | Page size, ≤100 (default 25) |
page | int | no | Page number (default 1) |
status | string | no | WAIT/DONE/CANCEL/TIMEOUT |
from | string | no | ISO date/time — lower bound of date |
to | string | no | ISO date/time — upper bound of date |
GET https://sms-acktiwator.ru/api/v1/emails?status=WAIT&size=25&page=1
Authorization: ApiKey YOUR_API_KEY
Response (200):
{
"data": [ { "id": 12345, "site": "telegram.org", "email": "z@gmail.com",
"status": "WAIT", "value": null, "cost": "0.10",
"currency": "USD", "date": "2026-07-31T10:00:00Z", "message": null } ],
"meta": { "page": 1, "size": 25, "total": 1 }
}
2) POST /api/v1/emails — buy an activation
| Parameter | Type | Required | Description |
|---|---|---|---|
site | string | yes | Target site (any) |
domain | string | yes | Mailbox domain |
POST https://sms-acktiwator.ru/api/v1/emails
Authorization: ApiKey YOUR_API_KEY
Content-Type: application/x-www-form-urlencoded
site=telegram.org&domain=gmail.com
Response (201): {"data": Activation} with status="WAIT" and value=null.
Errors: 422 BAD_PARAMS — site/domain missing; 409 NO_OFFER — no mailboxes available for this pair (or insufficient balance).
3) GET /api/v1/emails/{id} — get an activation (check the code)
GET https://sms-acktiwator.ru/api/v1/emails/12345
Authorization: ApiKey YOUR_API_KEY
Response (200): {"data": Activation}. Poll this until a terminal status (DONE/CANCEL/TIMEOUT).
Errors: 404 NOT_FOUND — not found or belongs to another user.
4) DELETE /api/v1/emails/{id} — cancel an activation
DELETE https://sms-acktiwator.ru/api/v1/emails/12345
Authorization: ApiKey YOUR_API_KEY
Response: 204, no body. Cancels the activation and refunds the charge to your balance.
Errors: 404 NOT_FOUND — not yours/not found; 409 CANNOT_CANCEL — activation already closed (completed/cancelled/expired).
5) POST /api/v1/emails/{id}/reorder — buy again (same site/domain)
POST https://sms-acktiwator.ru/api/v1/emails/12345/reorder
Authorization: ApiKey YOUR_API_KEY
Response (201): {"data": Activation} — a new activation with the same site/domain as the original (its own status is irrelevant and unchanged).
Errors: 404 NOT_FOUND — the original activation is not yours/not found; 409 NO_OFFER — no mailboxes available.
6) POST /api/v1/emails/{id}/reuse — one more letter to the SAME address
POST https://sms-acktiwator.ru/api/v1/emails/12345/reuse
Authorization: ApiKey YOUR_API_KEY
Not to be confused with reorder: reorder buys a DIFFERENT mailbox, while reuse keeps the same address — which is exactly what sites that will not accept a second address require.
When available: the first code for the activation has arrived and no more than 20 minutes have passed since (reuse_until on the activation), no more than 3 reuses per activation, and the activation's provider supports it. All four conditions are visible up front in the reuse_until/reuse_left fields of GET /api/v1/emails/{id}: reuse_until: null means no reuse is possible for that activation.
Response (200): {"data": Activation} — the same activation (same id and email), back in WAIT. value keeps holding the PREVIOUS code until a new letter arrives: a change of value is how you detect the second letter.
Price: a reuse is charged as a regular activation on the same direction when the provider charges us for it, and is free when it does not. If the second letter never arrives before the window closes, the reuse charge is refunded automatically; the original activation price is not refunded — you already received the first code.
Errors: 404 NOT_FOUND — not yours/not found; 409 CANNOT_REUSE — window closed, limit reached, no code yet, or the provider does not support it; 429 CHANNEL_LIMIT — a previous reuse for this activation is still running.
Accepts idempotency_key (see below): repeating the request with the same key returns the earlier result and does not spend a second attempt.
7) POST /api/v1/emails/batch — buy several activations at once
| Parameter | Type | Required | Description |
|---|---|---|---|
count | int | yes | 1..10 |
site | string | yes | Target site (shared across the batch) |
domain | string | yes | Domain (shared across the batch) |
Response (201): {"data": [Activation, ...], "meta": {"info": string|null, "count": int}}. On partial success (stock ran out at item N) data contains only what was bought, meta.count is how many, and meta.info explains why it stopped.
Errors: 422 BAD_PARAMS — count outside 1..10, or site/domain missing.
8) GET /api/v1/emails/domains — domain and price catalog
GET https://sms-acktiwator.ru/api/v1/emails/domains
Authorization: ApiKey YOUR_API_KEY
Response (200):
{
"data": [
{ "name": "gmail.com", "cost": "0.15", "count": 42 },
{ "name": "outlook.com", "cost": "0.20", "count": 7 }
]
}
| Parameter | Type | Required | Description |
|---|---|---|---|
site | string | no | Target site to price the catalog for. Omitted — the default site |
The ?site= parameter does affect the result. Mailbox cost varies several-fold by target site, so the catalog is priced for the site you pass. Request domains with the same site you are going to buy for: prices taken for a different site will not match the real ones, and the purchase will return 409 NO_OFFER for a domain that looked available in the catalog.
Common to both contracts
GET /api/v1/transactions — balance operation history
Charges, top-ups and refunds on your account — for reconciliation. The method is not tied to a product and stays available even if activations or rentals are not enabled for you: this is your money. Envelope as in contract 1 ({data, meta}).
| Parameter | Type | Required | Description |
|---|---|---|---|
type | string | no | Filter by operation type (see type in the response). An unknown type yields an empty list, not an error |
from | string | no | Start date/time (ISO-8601 or YYYY-MM-DD) |
to | string | no | End date/time |
page | int | no | Page, from 1 |
size | int | no | Page size, 1..100 (default 25) |
GET https://sms-acktiwator.ru/api/v1/transactions?from=2026-09-01&size=50
Authorization: ApiKey YOUR_API_KEY
Response (200):
{
"data": [
{ "id": 987654, "type": "email_rent_payment", "direction": "out",
"amount": "0.0421", "currency": "USD",
"balance_before": "5.0000", "balance_after": "4.9579",
"description": "Аренда email #1000042 · abc123@zickmail.com · 2 сайтов · 24 ч · Qeex",
"date": "2026-09-02T10:05:00Z" }
],
"meta": { "page": 1, "size": 50, "total": 1 }
}
amount is always positive — the money direction is carried by direction: "in" (top-up, refund) or "out" (charge). Do not infer the sign from type: the type list grows, and a hardcoded mapping will silently lie one day.
Records are sorted newest first. The transaction_id from rental responses is the id here.
Contract 2 — Mailbox rental (multisite)
Base URL: https://sms-acktiwator.ru/api/v1/ + method name. Methods accept both GET and POST (GET for compatibility with the familiar format, POST as the more correct way for state-changing calls).
Success: {"success": true, "result": ...}. Error: {"success": false, "error": "..."} with a matching HTTP status (no code field).
Important for integrators — specifics of our implementation:
- minimum rental period is 12 hours (maximum is 1440 hours = 60 days);
- there is no rental cancellation — rentals are non-refundable;
- letters are served from our own database (a cron job syncs them from the provider roughly every 2 minutes), so they remain available after the rental period ends.
multisiteOffers — rental quote
Rental prices per domain for a specific set. The tariff is linear in the number of sites and in hours, so a "price per domain" detached from the set does not exist: ask for the quote with exactly the period and sites you are going to order with.
| Parameter | Type | Required | Description |
|---|---|---|---|
period | int | no | Hours, 12..1440 (default 12) |
sites | int | no | Number of sites, 1..50 (default 1) |
GET https://sms-acktiwator.ru/api/v1/multisiteOffers?period=24&sites=2
Authorization: ApiKey YOUR_API_KEY
Response (200):
{ "success": true, "result": [
{ "domain": "zickmail.com", "cost": "0.0421", "currency": "USD", "count": 12 }
] }
count — how many mailboxes of that domain are available. The price is deterministic for the triple (domain, site count, hours) and is not reserved: it does not drift on its own, and max_cost on multisiteOrder protects you from a tariff change between your two calls.
Errors: 422 — period outside 12..1440, sites outside 1..50, or a non-numeric value. Out-of-range values are not clamped: we do not silently re-price your request.
multisiteOrder — order a mailbox rental
| Parameter | Type | Required | Description |
|---|---|---|---|
domain | string | yes | Mailbox domain |
sites | string | yes | Comma-separated list of target sites |
period | int | yes | Hours, 12..1440 |
max_cost | string | no | Price cap in USD. If the rental costs more — 422 with no charge |
idempotency_key | string | no | Idempotency key (see the section above) |
POST https://sms-acktiwator.ru/api/v1/multisiteOrder
Authorization: ApiKey YOUR_API_KEY
Content-Type: application/x-www-form-urlencoded
domain=zickmail.com&sites=instagram.com,discord.com&period=12
Response (201):
{ "success": true, "result": {
"id": 1000042, "email": "abc123@zickmail.com", "expire": 43200,
"cost": "0.0421", "currency": "USD",
"transaction_id": 987654, "balance_before": "5.0000", "balance_after": "4.9579"
} }
expire — seconds until the rental expires. cost — the amount charged, as a string (not a float: over a long period float would lose cents). transaction_id, balance_before and balance_after point at the same operation in your GET /api/v1/transactions history, which makes reconciliation straightforward.
Errors: 422 — domain/sites missing, period outside 12..1440 ("Период аренды: 12..1440 часов"), malformed max_cost, or the price exceeds max_cost ("Цена выше переданного потолка max_cost", nothing charged); 409 — business decline (no mailboxes for the domain, insufficient balance).
multisiteInfo — rental status
Request: GET .../api/v1/multisiteInfo?id=1000042 (+ auth header)
Response (200):
{ "success": true, "result": { "id": 1000042, "email": "abc123@zickmail.com", "expire": 43180, "expired": false } }
After the period ends, expire becomes negative and expired is true (the rental record stays and letters remain accessible).
Errors: 404 — not yours/not found.
multisiteLetters — mailbox letters
Request: GET .../api/v1/multisiteLetters?id=1000042
Response (200):
{ "success": true, "result": [
{ "from": "noreply@discord.com", "subject": "Verify your email",
"data": "112233", "received_at": "2026-07-31T10:05:00Z" }
] }
Letters are served from our database, no provider call — available after the rental ends too.
Errors: 404 — not yours/not found.
multisiteExtend — extend a rental
| Parameter | Type | Required | Description |
|---|---|---|---|
id | int | yes | Rental ID |
period | int | yes | Extra hours, 12..1440 |
max_cost | string | no | Price cap for the top-up, in USD |
idempotency_key | string | no | Idempotency key |
Response (200):
{ "success": true, "result": {
"ok": true, "cost": "0.0421", "currency": "USD", "expire": 86400,
"transaction_id": 987655, "balance_before": "4.9579", "balance_after": "4.9158"
} }
cost is the price of this extension (not the rental total), expire — seconds until the new deadline.
Contract change (September 2026): the method used to return result: true|false, with declines arriving as HTTP 200. result is now an object and a decline arrives as a status — 409 with {"success": false, "error": "..."}. Testing the truthiness of result no longer works: an object is always truthy — check the HTTP status or the success field.
Errors: 422 — period outside 12..1440, malformed max_cost, or the price exceeds it; 404 — not yours/not found; 409 — business decline (insufficient balance, rental not active, provider refusal — money refunded in that case).
multisiteReorder — new rental with the same domain/sites
Request: POST .../api/v1/multisiteReorder with id (of the original rental) and period. Also accepts max_cost and idempotency_key.
Response (201): the same object as multisiteOrder (including cost, transaction_id, balance_before/balance_after) — a new rental on the same domain and site list as the original.
Errors: 404 — the original rental is not yours/not found; 409/422 — same as multisiteOrder.
Error codes
Contract 1 (activations), code field:
| HTTP | code | When |
|---|---|---|
| 401 | BAD_KEY | Key missing, not found, or inactive |
| 403 | BANNED | Account is banned |
| 403 | FORBIDDEN | Product (email activations) not enabled for the account |
| 404 | NOT_FOUND | Activation not found or belongs to another user |
| 409 | NO_OFFER | No mailboxes available for site/domain (incl. insufficient balance) |
| 409 | CANNOT_CANCEL | Activation already closed — cannot cancel |
| 409 | IDEMPOTENCY_IN_PROGRESS | A request with this idempotency_key is still running |
| 422 | BAD_PARAMS | Required parameters missing, count outside 1..10, or idempotency_key longer than 128 chars |
| 429 | CHANNEL_LIMIT | Per-key rate limit exceeded |
Contract 2 (rental), error field (no code):
| HTTP | error | When |
|---|---|---|
| 401 | "Bad API key" | Key missing, not found, or inactive |
| 403 | "Account is banned" | Account is banned |
| 403 | "Product disabled" | Product (mailbox rental) not enabled for the account |
| 404 | "Rental not found" | Rental is not yours or doesn't exist |
| 409 | reason text | Business decline (no mailboxes for the domain, insufficient balance) |
| 422 | "domain and sites required" | Required parameters missing |
| 422 | "Период аренды: 12..1440 часов" | period outside the allowed range |
| 422 | "Цена выше переданного потолка max_cost" | Price exceeded max_cost — nothing was charged |
| 409 | "Request with this idempotency_key is still in progress" | A request with this idempotency_key is still running |
| 429 | "Rate limit exceeded" | Per-key rate limit exceeded |
Examples
The key in every example is a placeholder, YOUR_API_KEY — replace it with your own.
Buy an activation and wait for the code
curl:
curl -X POST "https://sms-acktiwator.ru/api/v1/emails" \
-H "Authorization: ApiKey YOUR_API_KEY" \
-d "site=telegram.org" -d "domain=gmail.com"
# then poll:
curl "https://sms-acktiwator.ru/api/v1/emails/12345" \
-H "Authorization: ApiKey YOUR_API_KEY"
Python (requests):
import time
import requests
BASE = "https://sms-acktiwator.ru/api/v1"
HEADERS = {"Authorization": "ApiKey YOUR_API_KEY"}
r = requests.post(f"{BASE}/emails", headers=HEADERS,
data={"site": "telegram.org", "domain": "gmail.com"})
r.raise_for_status()
activation = r.json()["data"]
while True:
r = requests.get(f"{BASE}/emails/{activation['id']}", headers=HEADERS)
data = r.json()["data"]
if data["status"] == "DONE":
print("code:", data["value"])
break
if data["status"] in ("CANCEL", "TIMEOUT"):
raise RuntimeError(data["status"])
time.sleep(3)
JavaScript (fetch):
const BASE = "https://sms-acktiwator.ru/api/v1";
const HEADERS = { "Authorization": "ApiKey YOUR_API_KEY" };
async function buyAndWaitCode(site, domain) {
const created = await fetch(`${BASE}/emails`, {
method: "POST",
headers: { ...HEADERS, "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({ site, domain }),
}).then(r => r.json());
const id = created.data.id;
while (true) {
const { data } = await fetch(`${BASE}/emails/${id}`, { headers: HEADERS }).then(r => r.json());
if (data.status === "DONE") return data.value;
if (data.status === "CANCEL" || data.status === "TIMEOUT") throw new Error(data.status);
await new Promise(res => setTimeout(res, 3000));
}
}
Order a mailbox rental and read letters
curl:
curl -X POST "https://sms-acktiwator.ru/api/v1/multisiteOrder" \
-H "Authorization: ApiKey YOUR_API_KEY" \
-d "domain=zickmail.com" -d "sites=instagram.com,discord.com" -d "period=12"
curl "https://sms-acktiwator.ru/api/v1/multisiteLetters?id=1000042" \
-H "Authorization: ApiKey YOUR_API_KEY"
Python (requests):
r = requests.post(f"{BASE}/multisiteOrder", headers=HEADERS,
data={"domain": "zickmail.com", "sites": "instagram.com,discord.com", "period": 12})
order = r.json()["result"]
r = requests.get(f"{BASE}/multisiteLetters", headers=HEADERS, params={"id": order["id"]})
letters = r.json()["result"]
JavaScript (fetch):
const order = await fetch(`${BASE}/multisiteOrder`, {
method: "POST",
headers: { ...HEADERS, "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({ domain: "zickmail.com", sites: "instagram.com,discord.com", period: 12 }),
}).then(r => r.json());
const letters = await fetch(`${BASE}/multisiteLetters?id=${order.result.id}`, { headers: HEADERS })
.then(r => r.json());
Deprecated API
⚠️ /api/email-otp/get/, /api/email-otp/status/, /api/email-otp/cancel/ are deprecated — kept only for already-running integrations. For new integrations use only /api/v1/emails* (Contract 1 above).