Loading…

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/batch, а также заказ/продление аренды) — 20 запросов/мин на ключ. Счётчики раздельные: активации, аренда, котировка аренды и история транзакций считаются независимо.

Идемпотентность мутаций

Сетевой таймаут на запросе к нам не должен стоить вам второго списания. Любая мутация принимает ключ идемпотентности — параметром idempotency_key либо заголовком Idempotency-Key (до 128 символов):

  • покупка активацийPOST /api/v1/emails, POST /api/v1/emails/{id}/reorder, 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:

ПолеТипОписание
idintID активации
sitestringЦелевой сайт (как передан при покупке, нормализован)
emailstring|nullАрендованный email‑адрес
statusstringWAIT / DONE / CANCEL / TIMEOUT
valuestring|nullКод/значение из письма; null, пока не пришло
coststringСписанная с вас цена
currencystringВсегда "USD"
datestringISO‑8601 UTC, дата создания активации
messagestring|nullЗарезервировано (сейчас всегда null)

Статусы: WAIT — ожидание кода; DONE — код получен; CANCEL — активация отменена (средства возвращены); TIMEOUT — истекло время ожидания.

1) GET /api/v1/emails — список активаций

ПараметрТипОбязателенОписание
searchstringнетПоиск по site/email/domain
sizeintнетРазмер страницы, ≤100 (по умолчанию 25)
pageintнетНомер страницы (по умолчанию 1)
statusstringнетWAIT/DONE/CANCEL/TIMEOUT
fromstringнетISO‑дата/время — нижняя граница date
tostringнет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 — купить активацию

ПараметрТипОбязателенОписание
sitestringдаЦелевой сайт (любой)
domainstringдаДомен почтового ящика

Запрос:

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/batch — купить несколько активаций подряд

ПараметрТипОбязателенОписание
countintда1..10
sitestringдаЦелевой сайт (общий для всей пачки)
domainstringдаДомен (общий для всей пачки)

Ответ (201): {"data": [Activation, ...], "meta": {"info": string|null, "count": int}}. При частичном успехе (сток закончился на N‑й покупке) data содержит только купленные, meta.count — их число, meta.info поясняет причину остановки.

Ошибки: 422 BAD_PARAMScount вне 1..10 или не заданы site/domain.

7) 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 }
  ]
}
ПараметрТипОбязателенОписание
sitestringнетЦелевой сайт, под который считать цены. Без него — сайт по умолчанию

Параметр ?site= влияет на выдачу. Себестоимость ящика зависит от целевого сайта в разы, поэтому каталог считается именно под переданный сайт. Запрашивайте домены с тем же site, с которым потом будете покупать: цены, снятые под другой сайт, не совпадут с реальными, и на покупке вы получите 409 NO_OFFER по домену, который в каталоге выглядел доступным.

Общее для обоих контрактов

GET /api/v1/transactions — история операций с балансом

Списания, пополнения и возвраты по вашему аккаунту — для сверки расходов. Метод не привязан к продукту и доступен, даже если активации или аренда вам не подключены: это ваши деньги. Конверт — как у контракта 1 ({data, meta}).

ПараметрТипОбязателенОписание
typestringнетФильтр по типу операции (см. поле type в ответе). Неизвестный тип — пустая выдача, не ошибка
fromstringнетС какой даты/времени (ISO‑8601 или YYYY-MM-DD)
tostringнетПо какую дату/время
pageintнетСтраница, с 1
sizeintнетРазмер страницы, 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, с которыми будете заказывать.

ПараметрТипОбязателенОписание
periodintнетСрок в часах, 12..1440 (по умолчанию 12)
sitesintнетКоличество сайтов, 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.

Ошибки: 422period вне 12..1440, sites вне 1..50 либо нечисловое значение. Значения вне диапазона не подгоняются к границе: мы не пересчитываем ваш запрос в другую цену молча.

multisiteOrder — заказать аренду ящика

ПараметрТипОбязателенОписание
domainstringдаДомен ящика
sitesstringдаСписок целевых сайтов через запятую
periodintдаСрок в часах, 12..1440
max_coststringнетПотолок цены в USD. Если аренда стоит дороже — 422 без списания
idempotency_keystringнетКлюч идемпотентности (см. раздел выше)

Запрос:

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 становится отрицательным, а expiredtrue (аренда при этом остаётся в системе, письма продолжают быть доступны).

Ошибки: 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 — продлить аренду

ПараметрТипОбязателенОписание
idintдаID аренды
periodintдаДоп. срок в часах, 12..1440
max_coststringнетПотолок цены доплаты в USD
idempotency_keystringнетКлюч идемпотентности

Ответ (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.

Ошибки: 422period вне 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:

HTTPcodeКогда
401BAD_KEYКлюч не передан, не найден или неактивен
403BANNEDАккаунт заблокирован
403FORBIDDENПродукт (Email‑активации) не подключён аккаунту
404NOT_FOUNDАктивация не найдена или принадлежит другому пользователю
409NO_OFFERНет доступных ящиков по site/domain (в т.ч. недостаточно средств)
409CANNOT_CANCELАктивация уже закрыта — отменить нельзя
409IDEMPOTENCY_IN_PROGRESSЗапрос с этим idempotency_key ещё выполняется
422BAD_PARAMSНе заданы обязательные параметры, count вне 1..10 либо idempotency_key длиннее 128 символов
429CHANNEL_LIMITПревышен лимит запросов на ключ

Контракт 2 (аренда), поле error (без code):

HTTPerrorКогда
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/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 purchasesPOST /api/v1/emails, POST /api/v1/emails/{id}/reorder, POST /api/v1/emails/batch;
  • rentalsmultisiteOrder, 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 multisiteOrder and multisiteExtend means two different operations, not a repeat;
  • keys are isolated per API key: someone else's idempotency_key will never return their response;
  • if the first request is still running — 409 (IDEMPOTENCY_IN_PROGRESS in 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:

FieldTypeDescription
idintActivation ID
sitestringTarget site (as submitted, normalized)
emailstring|nullRented email address
statusstringWAIT / DONE / CANCEL / TIMEOUT
valuestring|nullCode/value from the letter; null until received
coststringAmount charged
currencystringAlways "USD"
datestringISO-8601 UTC, creation date
messagestring|nullReserved (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

ParameterTypeRequiredDescription
searchstringnoSearch over site/email/domain
sizeintnoPage size, ≤100 (default 25)
pageintnoPage number (default 1)
statusstringnoWAIT/DONE/CANCEL/TIMEOUT
fromstringnoISO date/time — lower bound of date
tostringnoISO 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

ParameterTypeRequiredDescription
sitestringyesTarget site (any)
domainstringyesMailbox 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_PARAMSsite/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/batch — buy several activations at once

ParameterTypeRequiredDescription
countintyes1..10
sitestringyesTarget site (shared across the batch)
domainstringyesDomain (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_PARAMScount outside 1..10, or site/domain missing.

7) 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 }
  ]
}
ParameterTypeRequiredDescription
sitestringnoTarget 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}).

ParameterTypeRequiredDescription
typestringnoFilter by operation type (see type in the response). An unknown type yields an empty list, not an error
fromstringnoStart date/time (ISO-8601 or YYYY-MM-DD)
tostringnoEnd date/time
pageintnoPage, from 1
sizeintnoPage 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.

ParameterTypeRequiredDescription
periodintnoHours, 12..1440 (default 12)
sitesintnoNumber 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: 422period 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

ParameterTypeRequiredDescription
domainstringyesMailbox domain
sitesstringyesComma-separated list of target sites
periodintyesHours, 12..1440
max_coststringnoPrice cap in USD. If the rental costs more — 422 with no charge
idempotency_keystringnoIdempotency 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: 422domain/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

ParameterTypeRequiredDescription
idintyesRental ID
periodintyesExtra hours, 12..1440
max_coststringnoPrice cap for the top-up, in USD
idempotency_keystringnoIdempotency 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 status409 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: 422period 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:

HTTPcodeWhen
401BAD_KEYKey missing, not found, or inactive
403BANNEDAccount is banned
403FORBIDDENProduct (email activations) not enabled for the account
404NOT_FOUNDActivation not found or belongs to another user
409NO_OFFERNo mailboxes available for site/domain (incl. insufficient balance)
409CANNOT_CANCELActivation already closed — cannot cancel
409IDEMPOTENCY_IN_PROGRESSA request with this idempotency_key is still running
422BAD_PARAMSRequired parameters missing, count outside 1..10, or idempotency_key longer than 128 chars
429CHANNEL_LIMITPer-key rate limit exceeded

Contract 2 (rental), error field (no code):

HTTPerrorWhen
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
409reason textBusiness 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_costnothing 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).