API для разработчиков
Забирайте новые компании прямо в CRM или свою систему: выдачи подписки, разовые заказы, справочники сфер и фильтров. Ответы — JSON.
Быстрый старт
- Войдите в кабинет → API и нажмите «Создать ключ». Ключ покажем один раз — сохраните его в надёжном месте.
- Передавайте ключ в каждом запросе в заголовке
Authorization: Bearer xk_…. - Проверьте, что всё работает, — запросите список выдач:
curl https://xelosa.ru/api/v1/deliveries -H "Authorization: Bearer xk_ВАШ_КЛЮЧ"import requests
API = "https://xelosa.ru/api/v1"
KEY = "xk_ВАШ_КЛЮЧ" # лучше хранить в переменной окружения
H = {"Authorization": f"Bearer {KEY}"} # дальше в примерах — эти заголовки
r = requests.get(f"{API}/deliveries", headers=H)
r.raise_for_status()
for d in r.json()["items"]:
print(d["id"], d["created_at"], d["rows"], "компаний")const API = "https://xelosa.ru/api/v1";
const KEY = "xk_ВАШ_КЛЮЧ"; // в Node лучше process.env.XELOSA_KEY
const H = { Authorization: `Bearer ${KEY}` }; // дальше в примерах — эти заголовки
const r = await fetch(`${API}/deliveries`, { headers: H });
const { items } = await r.json();
items.forEach(d => console.log(d.id, d.created_at, d.rows, "компаний"));
Базовый адрес — https://xelosa.ru/api/v1. Все даты — в UTC, формат ISO 8601
(2026-11-09T06:00:00Z). Деньги — в рублях, целым числом.
Ключ и вход
Ключ выдаётся в кабинете, раздел «API». У одного клиента — до 3 действующих ключей: например, отдельный для CRM и для тестов. Ключ даёт доступ только к вашим данным — тем же, что видны в кабинете. Утёк ключ — отзовите его в кабинете: он перестанет работать сразу.
Ключ можно передать и заголовком X-Api-Key: xk_…. В адресе
(?key=) ключ не принимаем — адреса попадают в логи и историю браузера.
Не вставляйте ключ в код страницы сайта, который видят ваши посетители: любой сможет его скопировать. Запросы к API делайте с вашего сервера.
Ограничения
- До 120 запросов в минуту на ключ. Больше — ответ
429, повторите через минуту. - Файлы выдач хранятся 30 дней, потом — ответ
410. Забирайте их вовремя. - Компании из выдачи отдаём страницами до 5 000 строк (
offset,limit). - Разовых заказов — до 3 в сутки, как и в кабинете.
Ошибки
При ошибке — HTTP-код и JSON одного вида. В details — что именно не так
в заказе (по-русски, можно показывать пользователю).
Пример ответа
{
"error": {
"code": "invalid",
"message": "Проверьте заказ.",
"details": [
"Нет сферы «судоходство» в каталоге — может, Судоходные компании?"
]
}
}| Код | Когда |
|---|---|
400 bad_request / bad_json | Неверные параметры или тело запроса не JSON |
401 unauthorized | Нет ключа, ключ неверный или отозван |
404 not_found | Нет такой выдачи, заказа или метода |
410 gone | Файл выдачи старше 30 дней — уже удалён |
422 invalid | Заказ не прошёл проверку — список в details |
429 rate_limited | Слишком много запросов |
500 server_error | Сбой у нас — повторите через несколько минут |
Методы
GET /me
Кто я
Код клиента, основная почта, компания и почты для выдач.
curl https://xelosa.ru/api/v1/me -H "Authorization: Bearer xk_ВАШ_КЛЮЧ"requests.get(f"{API}/me", headers=H).json()await (await fetch(`${API}/me`, { headers: H })).json();
Пример ответа
{
"code": "X-0042",
"email": "anna@coffeeopt.ru",
"company": "ООО «Кофе Опт»",
"recipients": [
"boss@coffeeopt.ru"
]
}GET /subscription
Подписка
Тариф, статус, что собираем и когда следующая выдача. Подписки нет — {"subscription": null}. Статусы: unpaid — не оплачена, checking — проверяем перевод, active — выдачи идут, renew — оплаченные выдачи кончились, paused, missing — перевод не нашли, closed.
curl https://xelosa.ru/api/v1/subscription -H "Authorization: Bearer xk_ВАШ_КЛЮЧ"sub = requests.get(f"{API}/subscription", headers=H).json()["subscription"]
if sub and sub["status"] == "renew":
print("Пора продлить:", sub["period_price_rub"], "₽")const { subscription: sub } = await (await fetch(`${API}/subscription`, { headers: H })).json();
if (sub?.status === "renew") console.log("Пора продлить:", sub.period_price_rub);
Пример ответа
{
"subscription": {
"tariff": "growth",
"tariff_name": "Рост",
"status": "active",
"weekly": 400,
"monthly": 1600,
"price_month_rub": 9900,
"period_months": 1,
"period_price_rub": 9900,
"deliveries_left": 3,
"next_delivery": "2026-11-09",
"weekday": 0,
"file_format": "csv_amo",
"filters": [
"email",
"mobile"
],
"ai_brief": "",
"segments": [
{
"niche_id": "coffee",
"niche": "Кофейни",
"cities": [
"Казань"
],
"share_percent": 75,
"weekly": 300
}
]
}
}GET /deliveries
Выдачи
Файлы, которые мы вам прислали: еженедельные выдачи, пробник и разовые заказы. Новые сверху. Чтобы забирать только новые, храните id последней забранной и передавайте его в since_id — тогда список идёт по возрастанию.
| Параметр | Что это |
|---|---|
limit | Сколько выдач вернуть, 1–100. По умолчанию 20 |
since_id | Только выдачи с id больше этого — для регулярной выгрузки |
curl "https://xelosa.ru/api/v1/deliveries?since_id=120" -H "Authorization: Bearer xk_ВАШ_КЛЮЧ"new = requests.get(f"{API}/deliveries", headers=H,
params={"since_id": last_id}).json()["items"]const { items } = await (await fetch(`${API}/deliveries?since_id=${lastId}`, { headers: H })).json();
Пример ответа
{
"items": [
{
"id": 121,
"kind": "weekly",
"created_at": "2026-11-09T06:02:11Z",
"expires_at": "2026-12-09T06:02:11Z",
"rows": 400,
"file_name": "xelosa_Кофейни_2026-11-09.csv",
"format": "csv",
"available": true,
"companies_url": "https://xelosa.ru/api/v1/deliveries/121/companies",
"file_url": "https://xelosa.ru/api/v1/deliveries/121/file"
}
]
}GET /deliveries/{id}/companies
Компании из выдачи
Строки файла в JSON — с английскими именами полей, телефоны, почты и мессенджеры — списками. Удобно сразу класть в CRM. Пустые поля — null или пустой список. Колонки ИИ-приоритета заполнены, только если он был включён.
| Параметр | Что это |
|---|---|
offset | С какой строки, по умолчанию 0 |
limit | Сколько строк, до 5 000. По умолчанию 1 000 |
format | json (по умолчанию) или csv — те же поля в CSV через «;», UTF-8 |
curl "https://xelosa.ru/api/v1/deliveries/121/companies?limit=500" -H "Authorization: Bearer xk_ВАШ_КЛЮЧ"def companies(delivery_id):
offset = 0
while True:
page = requests.get(f"{API}/deliveries/{delivery_id}/companies", headers=H,
params={"offset": offset, "limit": 1000}).json()
yield from page["items"]
offset += page["limit"]
if offset >= page["total"]:
break
for c in companies(121):
print(c["name"], c["inn"], c["phones"], c["emails"])async function* companies(id) {
for (let offset = 0; ; ) {
const p = await (await fetch(`${API}/deliveries/${id}/companies?offset=${offset}&limit=1000`, { headers: H })).json();
yield* p.items;
offset += p.limit;
if (offset >= p.total) break;
}
}
for await (const c of companies(121)) console.log(c.name, c.inn, c.phones);
Пример ответа
{
"delivery_id": 121,
"total": 400,
"offset": 0,
"limit": 1000,
"items": [
{
"name": "Кофейня «Зерно»",
"ai_priority": "Высокий · 86",
"ai_reason": "независимая кофейня, работает 3 года, рейтинг 4,8",
"legal_name": "ООО «Зерно»",
"inn": "1658027415",
"ogrn": "1191690012345",
"phones": [
"+7 (843) 021-47-14 (моб.)"
],
"emails": [
"hi@zerno-kzn.ru"
],
"website": "zerno-kzn.ru",
"telegram": [
"https://t.me/zerno_kzn"
],
"whatsapp": [],
"max": [],
"vk": [],
"other_social": [],
"address": "Казань, ул. Баумана, 12",
"legal_address": "Казань, ул. Баумана, 12",
"category": "Кофейня",
"okved": "56.10",
"status": "Действующая",
"registered": "14.03.2023",
"sme_category": "Микропредприятие",
"employees": 9,
"revenue_rub": 14200000,
"rating": 4.8,
"reviews": 312,
"hours": "пн–вс 8:00–22:00",
"branches": null,
"yandex_maps_url": "https://yandex.ru/maps/org/…",
"dgis_url": null,
"sources": [
"Яндекс Карты",
"сайт",
"ЕГРЮЛ"
]
}
]
}| Поле | Что в нём |
|---|---|
name, legal_name | Название на картах, юридическое название |
inn, ogrn, okved, status | Данные ЕГРЮЛ — с фильтром «только с ИНН» есть у каждой |
phones, emails | Списки; у телефона пометка «моб.», у почты — чья она, если видно |
website, telegram, whatsapp, max, vk, other_social | Сайт и мессенджеры |
address, legal_address, category, hours | Адрес, рубрика и часы работы с карт |
registered, sme_category, employees, revenue_rub | Дата регистрации, категория МСП, сотрудники, доход за прошлый год (данные налоговой) |
rating, reviews, branches | Рейтинг и отзывы на картах, филиалов в сети |
ai_priority, ai_reason | Оценка ИИ и почему — если включён ИИ-приоритет |
yandex_maps_url, dgis_url, sources | Карточки на картах и откуда данные |
GET /deliveries/{id}/file
Файл выдачи
Тот же файл, что приходит на почту: Excel или CSV для amoCRM / Битрикс24.
curl -OJ https://xelosa.ru/api/v1/deliveries/121/file -H "Authorization: Bearer xk_ВАШ_КЛЮЧ"r = requests.get(f"{API}/deliveries/121/file", headers=H)
open("xelosa_121.xlsx", "wb").write(r.content)const r = await fetch(`${API}/deliveries/121/file`, { headers: H });
require("fs").writeFileSync("xelosa_121.xlsx", Buffer.from(await r.arrayBuffer()));
GET /niches
Сферы
Каталог сфер — чтобы заказывать по точному названию. С q — поиск, без него — весь каталог с группами.
| Параметр | Что это |
|---|---|
q | Часть названия, например «стомат» |
curl -G "https://xelosa.ru/api/v1/niches" --data-urlencode "q=кофе" -H "Authorization: Bearer xk_ВАШ_КЛЮЧ"requests.get(f"{API}/niches", headers=H, params={"q": "кофе"}).json()await (await fetch(`${API}/niches?q=${encodeURIComponent("кофе")}`, { headers: H })).json();
Пример ответа
{
"items": [
{
"id": "coffee",
"name": "Кофейни",
"group": "Общепит"
},
{
"id": "tea_coffee_wholesale",
"name": "Чай и кофе оптом",
"group": "Продукты: производство и опт"
}
]
}GET /filters
Фильтры
Все фильтры: id для заказа, доплата за компанию в разовой покупке, с какого тарифа доступны в подписке, с чем не сочетаются.
curl https://xelosa.ru/api/v1/filters -H "Authorization: Bearer xk_ВАШ_КЛЮЧ"requests.get(f"{API}/filters", headers=H).json()await (await fetch(`${API}/filters`, { headers: H })).json();
Пример ответа
{
"items": [
{
"id": "email",
"name": "Только с почтой",
"hint": "",
"oneoff_rub_per_company": 1,
"subscription_from_tariff": "start",
"excludes": [],
"group": null
},
{
"id": "legal",
"name": "Только юрлица (ООО, АО)",
"hint": "",
"oneoff_rub_per_company": 0,
"subscription_from_tariff": "growth",
"excludes": [
"ip"
],
"group": null
}
]
}POST /orders/quote
Цена разовой покупки
Посчитать цену, ничего не заказывая. Тело — такое же, как у заказа. Сферу можно указать названием или id из /niches. count у сферы — сколько компаний из неё; не указали — делим поровну.
| Параметр | Что это |
|---|---|
rows | Сколько компаний: 500–20 000, шаг 100. Сфер: одна до 1 000, дальше +1 за каждую тысячу (до 10) |
segments | Список {niche, cities, count?}, до 5 городов в сфере |
filters | Список id фильтров, необязательно |
ai_brief | Для фильтра ai: {offer, ideal_client} — что вы продаёте и кто ваш лучший клиент |
format | xlsx, csv_amo или csv_b24 |
recipients | Кому прислать файл — почты из профиля. По умолчанию основная |
curl https://xelosa.ru/api/v1/orders/quote -H "Authorization: Bearer xk_ВАШ_КЛЮЧ" \
-H "Content-Type: application/json" \
-d '{"rows": 3000,
"segments": [{"niche": "Стоматологии", "cities": ["Казань", "Уфа"], "count": 2000},
{"niche": "Медицинские центры", "cities": ["Казань"], "count": 1000}],
"filters": ["email", "inn"]}'order = {
"rows": 3000,
"segments": [
{"niche": "Стоматологии", "cities": ["Казань", "Уфа"], "count": 2000},
{"niche": "Медицинские центры", "cities": ["Казань"], "count": 1000},
],
"filters": ["email", "inn"],
}
q = requests.post(f"{API}/orders/quote", headers=H, json=order).json()
print(q["price_rub"], "₽")const order = {
rows: 3000,
segments: [
{ niche: "Стоматологии", cities: ["Казань", "Уфа"], count: 2000 },
{ niche: "Медицинские центры", cities: ["Казань"], count: 1000 },
],
filters: ["email", "inn"],
};
const q = await (await fetch(`${API}/orders/quote`, {
method: "POST", headers: { ...H, "Content-Type": "application/json" },
body: JSON.stringify(order),
})).json();
Пример ответа
{
"rows": 3000,
"price_per_company_rub": 9,
"discount_percent": 10,
"price_rub": 24300,
"invoice_only": true,
"filters": [
"email",
"inn"
],
"rare_filters_warning": null,
"segments": [
{
"niche_id": "dentistry",
"niche": "Стоматологии",
"cities": [
"Казань",
"Уфа"
],
"share_percent": 67
}
],
"recipients": [
"anna@coffeeopt.ru"
],
"format": "xlsx"
}POST /orders
Разовая покупка
Тот же заказ, что в кабинете. В ответе — pay_url: страница оплаты с реквизитами, её открывает человек. Сумма больше 16 200 ₽ — invoice_only: true: на странице оплаты будет кнопка «Запросить счёт». После оплаты собираем файл — обычно 1–2 дня; он придёт на почты из recipients и появится в /deliveries.
curl https://xelosa.ru/api/v1/orders -H "Authorization: Bearer xk_ВАШ_КЛЮЧ" -H "Content-Type: application/json" -d @order.jsono = requests.post(f"{API}/orders", headers=H, json=order).json()
print("Оплатить:", o["pay_url"])const o = await (await fetch(`${API}/orders`, { method: "POST", headers: { ...H, "Content-Type": "application/json" }, body: JSON.stringify(order) })).json();
console.log("Оплатить:", o.pay_url);
Пример ответа
{
"id": 57,
"status": "awaiting_payment",
"created_at": "2026-11-03T18:20:00Z",
"rows": 3000,
"price_rub": 24300,
"format": "xlsx",
"recipients": [
"anna@coffeeopt.ru"
],
"segments": [
"…"
],
"filters": [
"email",
"inn"
],
"pay_url": "https://xelosa.ru/pay/…",
"invoice_only": true,
"delivery_id": null
}GET /orders/{id}
Статус заказа
Статусы: awaiting_payment → payment_checking (вы сообщили о переводе, сверяем) → collecting → ready (в delivery_id — выдача с файлом). Или declined. GET /orders — последние 50 заказов.
curl https://xelosa.ru/api/v1/orders/57 -H "Authorization: Bearer xk_ВАШ_КЛЮЧ"import time
while True:
o = requests.get(f"{API}/orders/57", headers=H).json()
if o["status"] in ("ready", "declined"):
break
time.sleep(1800) # раз в полчаса хватит
print(o["status"], o["delivery_id"])const o = await (await fetch(`${API}/orders/57`, { headers: H })).json();
Пример ответа
{
"id": 57,
"status": "ready",
"delivery_id": 133,
"pay_url": null
}Готовые сценарии
Каждую неделю — новые компании в CRM
Запускайте по расписанию (cron, планировщик задач) раз в день: скрипт заберёт только новые выдачи и запомнит, на какой остановился.
import json, os, pathlib, requests
API = "https://xelosa.ru/api/v1"
H = {"Authorization": f"Bearer {os.environ['XELOSA_KEY']}"}
STATE = pathlib.Path("xelosa_last_id.txt")
def to_crm(company):
# Здесь — запрос в вашу CRM: создать компанию или лид
print("→ CRM:", company["name"], company["phones"][:1], company["emails"][:1])
last = int(STATE.read_text()) if STATE.exists() else 0
for d in requests.get(f"{API}/deliveries", headers=H,
params={"since_id": last, "limit": 100}).json()["items"]:
if not d["available"]:
continue
offset = 0
while True:
page = requests.get(f"{API}/deliveries/{d['id']}/companies", headers=H,
params={"offset": offset, "limit": 1000}).json()
for c in page["items"]:
to_crm(c)
offset += page["limit"]
if offset >= page["total"]:
break
STATE.write_text(str(d["id"])) # запомнили — в следующий раз не повторим// Node 18+: XELOSA_KEY=xk_… node sync.mjs
import fs from "node:fs";
const API = "https://xelosa.ru/api/v1";
const H = { Authorization: `Bearer ${process.env.XELOSA_KEY}` };
const STATE = "xelosa_last_id.txt";
const get = async (url) => (await fetch(url, { headers: H })).json();
async function toCrm(c) {
// Здесь — запрос в вашу CRM
console.log("→ CRM:", c.name, c.phones[0], c.emails[0]);
}
let last = fs.existsSync(STATE) ? +fs.readFileSync(STATE, "utf8") : 0;
const { items } = await get(`${API}/deliveries?since_id=${last}&limit=100`);
for (const d of items) {
if (!d.available) continue;
for (let offset = 0; ; ) {
const p = await get(`${API}/deliveries/${d.id}/companies?offset=${offset}&limit=1000`);
for (const c of p.items) await toCrm(c);
offset += p.limit;
if (offset >= p.total) break;
}
fs.writeFileSync(STATE, String(d.id));
}
Разовая покупка из своей системы
POST /orders/quote— показать цену менеджеру.POST /orders— создать заказ, открытьpay_urlи оплатить.- Раз в полчаса —
GET /orders/{id}, пока статус неready. GET /deliveries/{delivery_id}/companies— забрать компании.
Вопросы по API
Пишите на data@xelosa.ru — с кодом клиента и, если есть, текстом ошибки. Ключ в письме не присылайте.