API
Отправка ссылок на индексацию и статус каждой из них — из вашего кода. Обычный HTTP и JSON, ключ создаётся в кабинете за минуту, отдельного согласования не требуется.
С чего начать#
Три шага: создать ключ в кабинете, отправить список ссылок, забрать статус каждой. Ниже — весь путь одной командой; всё остальное на этой странице подробности к нему.
# 1. Отправить ссылки
curl -X POST https://dobermanindexztoken.com/api/v1/tasks \
-H "X-Api-Key: ik_ВАШ_КЛЮЧ" \
-H "Content-Type: application/json" \
-d '{"urls": ["https://site.com/a", "https://site.com/b"]}'
# 2. Забрать статус каждой (id из ответа выше)
curl https://dobermanindexztoken.com/api/v1/tasks/965/urls \
-H "X-Api-Key: ik_ВАШ_КЛЮЧ"Ключ создаётся в кабинете, на странице «API и ключи». Он показывается один раз — в базе остаётся только хеш, и восстановить ключ невозможно. Потеряли — заведите новый, старый отзовите.
Ключ и авторизация#
Ключ передаётся заголовком. Два способа намеренно: Authorization привычен тем, кто ходил в другие API, а X-Api-Key — тем, у кого заголовок авторизации уже занят прокси или шлюзом.
X-Api-Key: ik_ВАШ_КЛЮЧ
# или
Authorization: Bearer ik_ВАШ_КЛЮЧКлючей на аккаунт можно завести до десяти — по одному на сервис, чтобы отозвать один, не трогая остальные. Отзыв действует сразу.
Ключ — это доступ к балансу. Он позволяет тратить токены, поэтому место ему в переменных окружения на сервере, а не в коде страницы и не в репозитории.
Формат ответа#
В каждом ответе есть поле success — в успешном и в ошибочном. Разбирать по HTTP-коду тоже можно, но клиентские библиотеки чаще смотрят в тело, и одно поле дешевле объяснить, чем таблицу кодов.
{ "success": true, "task": { ... } }
{ "success": false, "error": { "code": "insufficient_funds",
"message": "Недостаточно токенов",
"details": {} } }Поля внутри версии v1 не исчезают и не меняют смысл. Новые появляться могут — разбирайте ответ так, чтобы незнакомое поле не ломало код.
Отправка ссылок#
/api/v1/tasks| Поле | Обязательно | Что это |
|---|---|---|
urls | да | Массив адресов или одна строка с переводами строк |
product | нет | Код услуги, по умолчанию mass_index |
title | нет | Название — по нему задание проще найти в кабинете |
idempotency_key | нет | Своя строка на попытку. Повтор с тем же ключом вернёт то же задание и не спишет токены дважды |
curl -X POST https://dobermanindexztoken.com/api/v1/tasks \
-H "X-Api-Key: ik_ВАШ_КЛЮЧ" \
-H "Content-Type: application/json" \
-d '{
"product": "mass_index",
"urls": ["https://site.com/a", "https://site.com/b", "https://site.com/a"],
"title": "Августовский блог",
"idempotency_key": "blog-2026-08-23"
}'{
"success": true,
"charged_tokens": 6,
"balance_after": 4994,
"task": {
"id": 965,
"status": "queued",
"urls": { "total": 2, "crawled": 0, "indexed": 0, "errors": 0,
"rejected": 0, "duplicates": 1, "excluded_already_indexed": 0 },
"tokens": { "held": 6, "charged": 0, "refunded": 0 }
}
}Списывается не всё, что отправили. Повторы, битые адреса и уже проиндексированные ссылки отсеиваются до списания: в примере из трёх адресов приняты два, за них и заморожено 6 токенов. Сколько отсеяно и почему — в полях rejected, duplicates и excluded_already_indexed.
charged_tokens и balance_after есть в ответе намеренно: скрипт, отправляющий пачками, должен уметь остановиться сам, а не узнавать об исчерпанном балансе из отказа.
/api/v1/tasksВаши задания. Параметры: status, product, date_from, date_to, page, per_page (до 100).
/api/v1/tasks/{id}Одно задание со счётчиками и суммами.
/api/v1/tasks/{id}/cancelОтмена — пока задание не ушло в работу. У каждого задания есть окно на отмену: срок лежит в поле starts_at, признак — can_cancel. Внутри окна токены возвращаются на баланс целиком: за то, что не сделано, мы не берём.
После начала работы отмена невозможна, и возврата не будет — ответ 409. Ссылки к этому моменту уже поданы, обход идёт, и вернуть за него деньги значило бы отдать сделанное даром.
Статус каждой ссылки#
/api/v1/tasks/{id}/urlsГлавный вызов: что стало с каждым адресом. Параметры: status, q (поиск по адресу), page, per_page.
curl "https://dobermanindexztoken.com/api/v1/tasks/965/urls?status=crawled&per_page=200" \
-H "X-Api-Key: ik_ВАШ_КЛЮЧ"{
"success": true,
"task_id": 965,
"total": 2,
"urls": [
{
"url": "https://site.com/a",
"status": "crawled",
"crawled_at": "2026-08-23T10:23:16+00:00",
"first_crawled_at": "2026-08-23T10:23:16+00:00",
"crawl_count": 1,
"checked_at": null,
"billable": true,
"rejected_because": null
}
]
}Два поля — два разных факта, и путать их нельзя. crawled_at — по ссылке прошёл подтверждённый поисковый бот; это мы фиксируем сами, и время точное. checked_at — когда мы смотрели поисковую выдачу. Пустой checked_at означает «проверки не было», а не «страницы нет в индексе».
| status | Что это |
|---|---|
pending | В очереди, бот ещё не заходил |
crawled | Бот прошёл по ссылке |
indexed | Проверка нашла страницу в выдаче |
not_indexed | Проверка страницу не нашла |
error | Отправить не удалось |
Коды состояний не переводятся и не переименовываются — интеграции ветвятся по ним. Подписи на языке пользователя живут в кабинете, а не здесь.
Аккаунт и услуги#
/api/v1/accountБаланс в токенах и его пересчёт в доллары. Первый вызов любой интеграции: прежде чем слать ссылки, скрипт должен уметь спросить, хватит ли на них.
{
"success": true,
"account": {
"id": 4320,
"email": "you@example.com",
"lang": "ru",
"balance": { "total": 4980, "purchased": 4980, "bonus": 0, "usd": "4.98" }
}
}/api/v1/productsУслуги и цены. Нужен, чтобы не зашивать коды и стоимость в свой код: цена меняется у нас, а ломается — у вас.
/api/v1/balance/historyДвижения токенов: пополнения, заморозки, списания, возвраты. Параметр direction отделяет приход от расхода. Нужна тем, кто ведёт свой учёт расходов: считая их по своим же вызовам, вы разойдётесь с нами на первом же возврате, о котором не знали.
Вебхуки#
Опрашивать статус в цикле не нужно. Подпишитесь на события — мы сами постучимся на ваш адрес, когда задание завершится.
/api/v1/webhookscurl -X POST https://dobermanindexztoken.com/api/v1/webhooks \
-H "X-Api-Key: ik_ВАШ_КЛЮЧ" \
-H "Content-Type: application/json" \
-d '{"url": "https://ваш-сервис.ру/hook", "events": ["task.completed"]}'В ответе придёт secret — единственный раз. Им подписывается каждая доставка.
Как проверить, что стучимся мы
В каждой доставке есть заголовок X-Indexer-Signature — HMAC-SHA256 от тела запроса вашим секретом. Сравнивайте его постоянным по времени сравнением.
import hmac, hashlib
def is_ours(body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)Не ответили 2xx — попробуем ещё: через минуту, две, пять, пятнадцать, полчаса и дальше раз в час. Журнал доставок с ответами вашего сервера виден через GET /webhooks/{id}/deliveries — он отвечает на вопрос «приходило ли вообще», не спрашивая нас.
| Вызов | Что делает |
|---|---|
GET /webhooks | Ваши подписки |
PATCH /webhooks/{id} | Изменить адрес, события или включить/выключить |
DELETE /webhooks/{id} | Удалить |
POST /webhooks/{id}/test | Тестовое событие — проверить связь до того, как она понадобится |
GET /events | Список событий. Он закрытый: подписка на выдуманное имя молча не сработала бы |
Ошибки#
Отказ — это всегда 4xx и всегда тело с error.code. Ветвитесь по коду, а не по тексту: текст переводится и может стать понятнее, код — нет.
| HTTP | code | Что произошло |
|---|---|---|
| 401 | invalid_api_key | Ключа нет, он отозван или скопирован не целиком |
| 402 | insufficient_funds | На балансе меньше, чем стоит отправка |
| 404 | not_found | Задания с таким номером у вас нет |
| 409 | conflict | Ни одной пригодной ссылки, или задание уже нельзя отменить |
| 422 | validation_error | Запрос не разобрался. В details.fields — что именно не так |
| 429 | rate_limited | Слишком часто. Подождите и повторите |
Повторы и пределы#
Повтор запроса не должен стоить дважды
Ответ потерялся, соединение оборвалось, скрипт перезапустился — обычное дело. Передайте idempotency_key: повтор с тем же ключом вернёт то же задание и не спишет токены второй раз. Ключ ваш и приватный — если сосед по сервису выберет такой же, ваши задания не пересекутся.
{ "urls": ["https://site.com/a"], "idempotency_key": "nightly-2026-08-23" }Пределы
per_page— до 100 в списках заданий и движений баланса, до 1000 в списке ссылок (по умолчанию 200).- Ключей на аккаунт — до 10.
- Размер одной отправки ограничен балансом, а не числом строк: списывается за принятые ссылки.
Слишком частые запросы получают 429. Разумный опрос статуса — раз в минуту; лучше вебхук, тогда опрашивать не придётся вовсе.
Примеры на языках#
Python
import httpx
API = "https://dobermanindexztoken.com/api/v1"
KEY = "ik_ВАШ_КЛЮЧ"
head = {"X-Api-Key": KEY}
with httpx.Client(timeout=30) as client:
created = client.post(f"{API}/tasks", headers=head, json={
"urls": ["https://site.com/a", "https://site.com/b"],
"idempotency_key": "nightly-2026-08-23",
}).json()
if not created["success"]:
raise SystemExit(created["error"]["message"])
task_id = created["task"]["id"]
print("списано", created["charged_tokens"], "осталось", created["balance_after"])
rows = client.get(f"{API}/tasks/{task_id}/urls", headers=head).json()["urls"]
for row in rows:
# crawled_at — заход бота, checked_at — проверка выдачи. Пусто
# во втором означает, что проверки не было
print(row["url"], row["status"], row["crawled_at"])JavaScript
const API = 'https://dobermanindexztoken.com/api/v1';
const head = { 'X-Api-Key': process.env.INDEXER_KEY, 'Content-Type': 'application/json' };
const created = await fetch(`${API}/tasks`, {
method: 'POST',
headers: head,
body: JSON.stringify({ urls: ['https://site.com/a'], idempotency_key: 'nightly-1' })
}).then((r) => r.json());
if (!created.success) throw new Error(created.error.message);
const { urls } = await fetch(`${API}/tasks/${created.task.id}/urls`, { headers: head })
.then((r) => r.json());
console.table(urls.map(({ url, status, crawled_at }) => ({ url, status, crawled_at })));PHP
<?php
$api = 'https://dobermanindexztoken.com/api/v1';
$key = getenv('INDEXER_KEY');
$ch = curl_init("$api/tasks");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["X-Api-Key: $key", 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'urls' => ['https://site.com/a', 'https://site.com/b'],
'idempotency_key' => 'nightly-2026-08-23',
]),
]);
$created = json_decode(curl_exec($ch), true);
curl_close($ch);
if (!$created['success']) {
exit($created['error']['message']);
}
echo "Задание {$created['task']['id']}, списано {$created['charged_tokens']}\n";Обход сайта
Отдельный вызов, потому что заказывается иначе: не списком ссылок, а адресом карты сайта. Сколько там адресов, знает только сама карта — поэтому стоимость становится известна после её чтения, а не в момент заказа.
curl -X POST https://dobermanindexztoken.com/api/v1/site-crawl \
-H "X-Api-Key: ik_ВАШ_КЛЮЧ" \
-H "Content-Type: application/json" \
-d '{
"source": "https://site.ru/sitemap.xml",
"source_kind": "sitemap",
"title": "Обход перед переездом"
}'source_kind — sitemap или list. Дальше задание живёт по общим правилам: состояние читается через GET /tasks/{id}, строки — через GET /tasks/{id}/urls, отмена до старта — как у остальных заданий.
Работаете с ИИ-агентами? Те же действия доступны по протоколу MCP — агент сам отправляет ссылки и читает статусы, без обёртки на HTTP. Как подключить.
Ключ создаётся за минуту
Регистрация, страница ключей, первый запрос — без согласований и без карты. Пробные десять ссылок проходят тем же путём, что и платные: тот же ответ, тот же отчёт.