Treka.eu Partner API

Посібник з інтеграції для корпоративних клієнтів — з прикладами, які можна скопіювати й запустити.

Базова адреса всіх запитів: https://treka.eu/api/v1. Кожен приклад нижче — робочий curl; підставте свій токен і виконайте.

1Автентифікація

Токен видає Treka.eu (менеджер або адмін-панель). Додавайте його в заголовок Authorization кожного запиту. Токен несе скоупи: leads:read, leads:write, trips:read, trips:write, webhooks:read. Якщо токену бракує потрібного скоупу — відповідь 403.

# Перевірте токен: хто ви, які скоупи й ліміти
curl https://treka.eu/api/v1/me \
  -H "Authorization: Bearer <ВАШ_ТОКЕН>"
{
  "id": 12,
  "name": "Ваша компанія",
  "status": "active",
  "sees_all_leads": false,
  "rate_limit_per_min": 120,
  "abilities": ["leads:read", "leads:write"],
  "webhook": { "configured": true, "url": "https://ваш-сервер/трека-хук" }
}

2Заявка у довільній формі («як у чаті»)

Найпростіший спосіб віддати заявку: надішліть сирий текст — так, як його написав би пасажир чи диспетчер. Той самий класифікатор, що читає стрічку спільнот, сам вичитає маршрут, дату, кількість пасажирів і телефон. Нічого структурувати наперед не треба.

POST/messages — скоуп leads:write

curl -X POST https://treka.eu/api/v1/messages \
  -H "Authorization: Bearer <ВАШ_ТОКЕН>" \
  -H "Content-Type: application/json" \
  -d '{
        "text": "Треба з Києва до Варшави 20 липня, 3 людини, +380631112233",
        "author_name": "Олена"
      }'

Розпізнавання йде асинхронно, тож відповідь одразу — 202 Accepted зі статусом pending:

{
  "data": {
    "id": 84213,
    "status": "pending",
    "text": "Треба з Києва до Варшави 20 липня, 3 людини, +380631112233",
    "author_name": "Олена",
    "leads": [],
    "created_at": "2026-07-20T09:14:02+00:00"
  }
}
Як забрати результат. Готові ліди приходять вебхуком lead.created (або lead.matched, якщо заявка збіглася з вашим зареєстрованим маршрутом) — див. розділ 6. Якщо вебхуків не налаштовано — опитайте статус (нижче).

Опитати статус: GET/messages/{id}

Скоуп leads:read. Опитуйте, доки status не стане relevantleads) або irrelevant (у тексті заявки немає).

curl https://treka.eu/api/v1/messages/84213 \
  -H "Authorization: Bearer <ВАШ_ТОКЕН>"
{
  "data": {
    "id": 84213,
    "status": "relevant",
    "leads": [
      {
        "id": 550141,
        "direction": "ua_pl",
        "from": { "city": "Київ", "key": "kyiv" },
        "to": { "city": "Варшава", "key": "warsaw" },
        "travel_date": "2026-07-20",
        "passengers": 3,
        "phone": "+380631112233"
      }
    ]
  }
}
Ідемпотентність. Повторна відправка того самого тексту вашою компанією поверне ту саму заявку, а не дубль. Різні пасажири на одному маршруті не зливаються — вони розрізняються за телефоном у тексті.

3Ключі міст

Поля from_key, to_key та cities приймають канонічний ключ міста з газетира — kyiv, berlin, warsaw. Ключі не завжди вгадуються (частина латиницею, а частина кирилицею чи поштовим індексом), тож не вигадуйте їх — знайдіть у довіднику.

GET/cities — будь-який валідний токен, скоуп не потрібен

# Резолвимо назву в точний ключ — точний збіг повертається першим
curl "https://treka.eu/api/v1/cities?q=Львів" \
  -H "Authorization: Bearer <ВАШ_ТОКЕН>"
{
  "data": [
    { "key": "lviv", "name": "Львів",
      "country": { "code": "ua", "name": "Україна" } }
  ],
  "meta": { "total": 1, "per_page": 50, "current_page": 1 }
}
ПараметрОпис
qПошук за назвою або ключем; також резолвить довільний текст у ключ (q=Львів).
countryФільтр за ISO-кодом країни (ua, de, pl).
per_page / pageПагінація (макс. 200 на сторінку).
Не хочете морочитися з ключами? POST /messages (розділ 2) читає місто з тексту сам — там ключі не потрібні взагалі.

4Структурована заявка (повний контроль)

Якщо ви вже маєте розібрані поля й хочете синхронну відповідь із готовим лідом — надсилайте POST /leads. Міста — це канонічні ключі газетира (kyiv, berlin…), телефон обовʼязковий.

POST/leads — скоуп leads:write

curl -X POST https://treka.eu/api/v1/leads \
  -H "Authorization: Bearer <ВАШ_ТОКЕН>" \
  -H "Content-Type: application/json" \
  -d '{
        "from_key": "kyiv",
        "to_key": "berlin",
        "travel_date": "2026-07-20",
        "passengers": 2,
        "phone": "+380631112233",
        "comment": "Дві валізи, заберіть від дому"
      }'

Відповідь — 201 Created з готовим лідом у полі data.

5Читання фіду лідів

GET/leads — скоуп leads:read. За замовчуванням повертає ліди, що збігаються з вашими маршрутами. Фільтри — через query-параметри.

curl "https://treka.eu/api/v1/leads?direction=ua_pl&date_from=2026-07-18&per_page=50" \
  -H "Authorization: Bearer <ВАШ_ТОКЕН>"
ПараметрОпис
scopemine (типово) або all — весь фід (потрібен контракт sees_all_leads).
directionНапрямок, напр. ua_de, ua_pl.
from / toКанонічні ключі міст.
countryISO-код країни на будь-якому кінці напрямку.
date_from / date_toДіапазон дати поїздки (Y-m-d).
per_page / pageПагінація (макс. 100 на сторінку).

6Маршрути

Щоб фід і вебхуки lead.matched звужувалися до ваших коридорів — зареєструйте маршрути. Напрямок виводиться з міст автоматично.

POST/trips — скоуп trips:write

curl -X POST https://treka.eu/api/v1/trips \
  -H "Authorization: Bearer <ВАШ_ТОКЕН>" \
  -H "Content-Type: application/json" \
  -d '{ "cities": ["kyiv", "warsaw"], "pickup_radius_km": 100 }'

Керування: GET /trips, PATCH /trips/{id}, DELETE /trips/{id}.

7Вебхуки

Коли заявку розпізнано, Treka.eu робить POST на ваш webhook_url з подією lead.created або lead.matched. URL і секрет налаштовує адмін-панель Treka.eu; поточну конфігурацію видно через GET /webhooks.

{
  "event": "lead.matched",
  "occurred_at": "2026-07-20T09:14:05+00:00",
  "data": { /* той самий обʼєкт лід, що й у GET /leads */ }
}

Перевірка підпису

Кожен запит несе заголовки X-Treka-Event, X-Treka-Timestamp і X-Treka-Signature. Перед обробкою перевірте підпис:

// PHP
$raw = file_get_contents('php://input');
$expected = 'sha256=' . hash_hmac(
    'sha256',
    $_SERVER['HTTP_X_TREKA_TIMESTAMP'] . '.' . $raw,
    $webhookSecret,
);
if (! hash_equals($expected, $_SERVER['HTTP_X_TREKA_SIGNATURE'])) {
    http_response_code(403);
    exit;
}
// підпис валідний — обробляйте, і відповідайте 2xx для підтвердження
// Node.js
const crypto = require('crypto');
const expected = 'sha256=' + crypto
    .createHmac('sha256', webhookSecret)
    .update(req.headers['x-treka-timestamp'] + '.' + rawBody)
    .digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(req.headers['x-treka-signature']))) {
    return res.sendStatus(403);
}

Відповідайте 2xx, щоб підтвердити доставку. Невдалі доставки повторюються з наростаючою затримкою; лог — GET /webhooks/deliveries.

8Успішні коди

HTTPКоли
200Успіх (читання, оновлення, видалення).
201Створено (структурований лід POST /leads, маршрут POST /trips).
202Заявку у довільній формі прийнято, розпізнавання триває.

9Помилки

Будь-яка помилка — єдиний конверт зі стабільним кодом code. Гілкуйтеся у коді саме по ньому, а не по тексту message (він українською й може змінюватися). Поле errors є лише для validation_failed.

{
  "code": "scope_missing",
  "message": "Токену бракує потрібного скоупу."
}
# приклад validation_failed
{
  "code": "validation_failed",
  "message": "Перевірте поля запиту.",
  "errors": { "text": ["The text field is required."] }
}
codeHTTPЗначення
unauthenticated401Токен відсутній або недійсний.
invalid_token403Токен не належить партнерському акаунту.
access_suspended403Партнерський доступ призупинено.
scope_missing403Токену бракує потрібного скоупу (ability).
plan_restricted403Дію не включено у ваш тариф (напр. `scope=all`).
forbidden403Доступ заборонено.
not_found404Ресурс не існує або не належить вам.
method_not_allowed405HTTP-метод не підтримується для цього ресурсу.
validation_failed422Помилка валідації; деталі полів — у `errors`.
route_limit_reached422Досягнуто ліміту активних маршрутів тарифу.
rate_limited429Перевищено ліміт запитів (`rate_limit_per_min`).
server_error500Внутрішня помилка сервера.