Documentation
Інтеграція та формат даних IntentD
Технічні специфікації для розробників розширень і дата-інженерів на боці покупця. Усе, що потрібно, щоб почати надсилати події або читати вигрузки.
01 · Publishers
SDK Quickstart
SDK працює в background script розширення і не потребує доступу до DOM сторінки. Бандл збирається в кабінеті персонально для розширення: ключі, ключ шифрування та ID розширення вже всередині, викликати init вручну не потрібно. До згоди користувача SDK нічого не збирає — як влаштований запит згоди.
# Кабінет → Розширення → SDK → Завантажити
# Файл intentd-<name>.min.js уже містить ключі та конфігурацію.
cp ~/Downloads/intentd-my-extension.min.js ./extension/intentd.min.js // background.js — першим рядком, на верхньому рівні.
// init викликається автоматично; слухачі мають реєструватися
// при старті service worker, інакше Manifest V3 не доставить події.
import './intentd.min.js';
// Необов'язково: статус і ручне надсилання.
// const status = await IntentD.status();
// await IntentD.flush(); Вимоги до маніфесту
-
manifest_version: 3— SDK не використовує eval і не підвантажує код ззовні. -
storage,alarms,unlimitedStorage— події накопичуються локально й ідуть пакетом раз на добу. -
webNavigation(або tabs) — джерело подій навігації. -
api.intentd.ioу host_permissions.
Перед завантаженням вкажіть у кабінеті ID розширення з магазину: бандл відмовляється працювати всередині будь-якого іншого розширення і повідомляє про це.
02 · Publishers
Ingest API
- Base URL
- https://api.intentd.io/v1
- Автентифікація
- X-API-Key + HMAC-SHA256 по тілу
Ендпоінти
| Метод | Шлях | Призначення | Ліміт |
|---|---|---|---|
| POST | /sdk/register | Реєстрація установки: сесія та ідентифікатор пакета. Ідемпотентна. | 120 запитів / хв з IP |
| POST | /telemetry/bucket | Зашифрований пакет подій (X25519 + AES-256-GCM). Раз на добу або достроково. | 48 пакетів / добу на установку |
| POST | /sdk/report-tamper | Повідомлення SDK про провалену перевірку цілісності. | 30 запитів / хв з IP |
Приклад запиту
POST /v1/telemetry/bucket HTTP/1.1
Host: api.intentd.io
Content-Type: application/json
X-API-Key: ext_...
X-Timestamp: 1758000000
# hex(HMAC-SHA256(secret, "intentd-v2|bucket|<X-Timestamp>|<X-API-Key>|" + hex(SHA-256(body))))
X-Signature: d49d3b20...
{
"bucket_id": "7c0e…", "session_id": "2b91…",
"ephemeral_public_key": "base64(32 байти)",
"iv": "base64(12 байтів)",
"encrypted_key": "base64(48 байтів)",
"ciphertext": "base64(AES-256-GCM пакета INTD)",
"events_count": 1234, "bytes_size": 45678, "bucket_version": 1,
"client_ts": 1758000000, "fingerprint_hash": "5c9a96…"
} Коди помилок
| HTTP | Код | Значення |
|---|---|---|
| 400 | BUCKET_INVALID_FORMAT | Пакет не розшифрувався або не пройшов перевірку формату і CRC32 |
| 401 | API_KEY_REVOKED | Ключ відкликано — SDK вимикається |
| 401 | INVALID_SIGNATURE | HMAC-підпис не збігся з тілом запиту |
| 401 | CLOCK_SKEW | Годинник клієнта розходиться більше ніж на 5 хвилин; у відповіді server_time |
| 402 | SUBSCRIPTION_INACTIVE | Немає активної підписки — події залишаються в черзі |
| 403 | WRONG_EXTENSION | Бандл запущено не в тому розширенні, для якого його випущено |
| 403 | FINGERPRINT_MISMATCH | Оточення не збігається з сесією — SDK реєструється заново |
| 409 | BUCKET_ALREADY_RECEIVED | Цей пакет уже прийнято |
| 413 | BUCKET_TOO_LARGE | Більше ніж 10 000 подій або 10 МБ — SDK ділить пакет |
| 429 | RATE_LIMITED | Перевищено ліміт запитів або пакетів на добу |
На мережевих помилках, 429 і 503 SDK зберігає чергу й повторює надсилання раз на годину. Двійковий формат пакета та схема шифрування описані відкрито — специфікація INTD v1.
03 · Data Buyers
Схема даних
Один рядок Parquet — одна очищена подія. Полів із персональними даними в схемі немає за побудовою: вони відкидаються в браузері, до надсилання.
| Поле | Тип | Опис |
|---|---|---|
| event_id | String | Унікальний GUID події |
| timestamp | Int64 | Unix Timestamp у мілісекундах, UTC |
| anon_uid | String | HMAC-хеш сесії користувача, незворотний |
| clean_url | String | URL після вирізання PII-параметрів |
| search_query | String | Витягнутий пошуковий інтент, якщо він є |
| lang | String | Мова браузера, BCP 47 |
| geo_country | String | ISO-код країни, визначається за IP на edge growth+ |
| device_type | String | desktop / mobile / tablet growth+ |
| domain | String | Кореневий домен без піддоменів |
Data Buyers
Data Provenance
- Усі події надходять лише від користувачів, які явно натиснули «Дозволити» в запиті згоди (GDPR ст. 6(1)(a)). До згоди SDK не створює ідентифікатор і не зберігає події.
- Кожен прийнятий пакет несе версію тексту згоди; сервер відхиляє пакети без неї і фіксує версію в журналі прийому. При зміні тексту згоду запитують заново.
- При відкликанні згоди SDK припиняє збір і видаляє ненадіслані події на пристрої; наступна видача згоди створює новий, не пов’язаний із попереднім псевдонім.
- Факт і час згоди конкретного користувача на сервері не зберігаються: доказом слугує сам прийнятий пакет і зафіксована версія тексту.
04 · Data Buyers
Зберігання і доставка
- Формат
- Parquet + LZ4
- Сховище
- AWS S3
- Hot-доступ
- 30 днів
- Архів
- 90 днів
Структура шляхів
year=YYYY/month=MM/day=DD/tenant=<key_id>__<bucket_id>.parquet.lz4 Партиціонування за датою та орендарем дозволяє читати потрібний зріз без повного сканування бакета. Growth і вище додатково підтримують синхронізацію у ваш власний bucket.
05 · Data Buyers
Приклади читання
Вигрузка читається будь-яким стандартним Parquet-стеком. Нижче — мінімальні приклади на Python і Go.
import pandas as pd
# Денна партиція орендаря в S3.
path = "s3://intentd-delivery/year=2026/month=09/day=11/tenant=ext_acme__7c0e.parquet.lz4"
frame = pd.read_parquet(
path,
columns=["timestamp", "domain", "search_query", "geo_country"],
storage_options={
"key": "YOUR_ACCESS_KEY",
"secret": "YOUR_SECRET_KEY",
},
)
top_domains = frame.groupby("domain").size().sort_values(ascending=False).head(20)
print(top_domains) package main
import (
"context"
"log"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/s3"
)
func main() {
ctx := context.Background()
cfg, err := config.LoadDefaultConfig(ctx)
if err != nil {
log.Fatal(err)
}
client := s3.NewFromConfig(cfg)
object, err := client.GetObject(ctx, &s3.GetObjectInput{
Bucket: ptr("intentd-delivery"),
Key: ptr("year=2026/month=09/day=11/tenant=ext_acme__7c0e.parquet.lz4"),
})
if err != nil {
log.Fatal(err)
}
defer object.Body.Close()
// Далі — будь-який Parquet-рідер, наприклад parquet-go.
log.Printf("отримано %d байтів", *object.ContentLength)
}
func ptr(s string) *string { return &s } Готові підключитися?
Створіть акаунт, щоб отримати ключі та зарезервувати вигрузку. Якщо потрібен семпл даних до підписання — напишіть нам.
Повна OpenAPI-специфікація порталу лежить у репозиторії: portal/docs/swagger.yaml. Публічний hosted-варіант з’явиться разом з особистим кабінетом — повідомити про потребу.