API записи

Все эндпоинты записи находятся под /api/v1 и требуют Bearer-токена со скоупом write.

Authorization: Bearer <api-key>

Тенант определяется по ключу. ID тенанта не фигурирует в URL.


Режим надёжности

Каждый эндпоинт записи принимает необязательный заголовок X-Letopis-Mode:

Значение Ответ Гарантия
strict 201 после записи в MongoDB Синхронно; подтверждено до ответа
durable 202 + тикет Очередь Redis Streams; воркер пишет асинхронно
fast 202 + тикет In-memory очередь; максимальная пропускная способность

При отсутствии заголовка применяется настроенный reliability_mode коллекции (по умолчанию durable).


Идемпотентность

Для предотвращения дублей при повторе — передайте клиентский ключ:

  • Заголовок Idempotency-Key, или
  • Поле event_id в теле запроса (приоритет выше).

Если тот же ключ поступает повторно в течение окна дедупликации (по умолчанию 24 ч), сервер воспроизводит оригинальный ответ. Второе событие не записывается.


Ingest полного состояния

POST /api/v1/collections/{collection}/entities/{entityId}/state

Отправьте полное текущее состояние сущности. Сервер вычислит дифф относительно последнего известного состояния.

Тело запроса

{
  "state": {
    "title": "ООО Ромашка",
    "amount": 50000,
    "stage": "prospect"
  },
  "event_id": "evt-001",
  "author_id": "user-42",
  "source": "crm-backend",
  "ts_source": "2026-06-01T10:00:00Z",
  "expected_version": 3
}
Поле Тип Обязательное Описание
state object Да Полное текущее состояние сущности
op string Нет create или update; определяется автоматически
event_id string Нет Клиентский ID для идемпотентности
author_id string Нет Кто сделал изменение
source string Нет Система-источник
ts_source RFC3339 Нет Время изменения в системе-источнике
expected_version integer Нет Оптимистичная блокировка; 409 при несовпадении
meta object Нет Произвольные метаданные

Ingest готового диффа

POST /api/v1/collections/{collection}/entities/{entityId}/diff
{
  "diff": [
    {"path": "amount", "op": "change", "old": 50000, "new": 75000},
    {"path": "stage",  "op": "change", "old": "prospect", "new": "qualified"}
  ],
  "author_id": "user-42"
}

Удаление сущности

POST /api/v1/collections/{collection}/entities/{entityId}/delete

Записывает событие delete. Состояние сущности очищается; история (события и слепки) сохраняется. Для физического удаления (GDPR) используйте Admin API (purge).


Пакетная запись

POST /api/v1/collections/{collection}/batch
{
  "writes": [
    {
      "entity_id": "deal-1",
      "type": "state",
      "state": {"title": "ООО Ромашка", "amount": 75000}
    },
    {
      "entity_id": "deal-2",
      "type": "diff",
      "diff": [{"path": "stage", "op": "change", "old": "prospect", "new": "won"}]
    }
  ]
}

Элементы обрабатываются независимо; ошибка одного не откатывает другие.


Опрос тикета

GET /api/v1/tickets/{ticketId}
{
  "ticket_id": "tkt_01hx...",
  "status": "stored",
  "entity_id": "deal-1",
  "collection": "crm.deals",
  "version": 4,
  "ts_stored": "2026-06-02T09:00:01Z"
}

Статус: accepted → processing → stored (успех) или failed (с полем error).