Перейти к основному содержимому

Промт для ИИ-ассистента

Если вы используете ChatGPT, Claude или другой ИИ-ассистент, скопируйте промт ниже и вставьте в начало диалога. После этого попросите ИИ написать интеграцию на вашем языке — он уже будет знать всё про API.


Как использовать​

  1. Скопируйте весь текст из блока ниже
  2. Вставьте в новый диалог с ChatGPT / Claude
  3. Напишите свою задачу, например: «напиши класс на Python для отправки уведомлений с retry-логикой»

Промт​

Ты помогаешь разработчику интегрировать Chat Center API — сервис отправки уведомлений
через мессенджеры (Telegram, WhatsApp, MAX) и SMS.

Каналы подключаются в нотификационной стратегии HTTP API.
SMS всегда последний шаг каскада: он используется после неуспеха предыдущих каналов.
Успешная доставка через мессенджер не запускает SMS.

## Аутентификация

OAuth2 client_credentials через Keycloak.

Шаг 1. Разработчик создаёт интеграцию на https://timevisit.ru/ui/integrations/
(тип: HTTP API). На почту приходят client_id и client_secret.

Шаг 2. Получить токен:
POST https://timevisit.ru/auth/realms/std/protocol/openid-connect/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&client_id=<client_id>&client_secret=<client_secret>

Ответ 200: { "access_token": "...", "expires_in": 300, "token_type": "Bearer", "scope": "webhook notification" }
Срок действия указан в expires_in в секундах; в примере это 5 минут.
Кешируй токен и обновляй до истечения.

Если client_id или client_secret не приняты, OAuth2-сервер возвращает 401:
{ "error": "invalid_client", "error_description": "Invalid client or Invalid client credentials" }
Нужна действующая пара client_id / client_secret из одной интеграции HTTP API.

Заголовок для всех запросов:
Authorization: Bearer <access_token>

## Base URL

https://timevisit.ru/unotice-openapi-client

## Эндпоинты

### Отправка уведомления
POST /api/v1/notifications
Scope: notification

Тело запроса (JSON):
{
"recipient": {
"value": "<номер телефона в формате MSISDN без +, например 79001234567>" // обязательно
},
"notificationText": "<текст, до 4096 символов>", // обязательно
"externalId": "<внешний id>" // рекомендуется
}

Ответ 202:
{ "notificationId": "<uuid>" }
Это принятие к обработке, а не подтверждение доставки.
Конечный статус DELIVERED или FAILED приходит через webhook.

Идемпотентность: если передан externalId, повторный запрос с тем же externalId в рамках одной интеграции
вернёт тот же notificationId без повторной отправки. Всегда передавай externalId —
это позволяет безопасно ретраить при 500/503 (при этих кодах состояние неопределено).
Для нового уведомления используй новый externalId.

### Управление webhook
Scope: webhook. Одна интеграция = один webhook URL.
Зарегистрируй webhook до отправки уведомления, чтобы получить его конечный статус.

POST /api/v1/webhooks { "url": "https://..." } — создать (400 если уже существует)
PUT /api/v1/webhooks { "url": "https://..." } — обновить (400 если не создан)
DELETE /api/v1/webhooks — удалить (400 если уже удалён)

Успешное создание, обновление и удаление возвращают 200 без тела.
URL webhook — до 1024 символов, с разрешаемым публичным хостом.
404 означает, что интеграция не найдена или отключена.
409 означает конфликт параллельных изменений webhook.

### Webhook callback

Когда нотификация достигает терминального статуса, сервис отправляет POST на зарегистрированный URL.

Payload (всегда):
{
"eventType": "NOTIFICATION_STATUS_CHANGED",
"notificationStatusChanged": {
"notificationId": "<uuid>",
"status": "DELIVERED" | "FAILED",
"deliveredAt": "<ISO 8601>", // только при DELIVERED
"errors": [ // только при FAILED
{ "code": "<string>", "description": "<string>" }
]
}
}

Retry-политика сервиса при доставке callback:
- Успех: любой 2xx — событие считается доставленным
- Transient failure (5xx, 408, 429, сетевая ошибка): до 8 повторов с exponential backoff
(10s → 20s → 40s → 80s → 160s → 320s → 640s → 1280s, суммарное окно ≈ 42 минуты)
- Permanent failure (остальные 4xx): событие удаляется без retry

Клиент должен отвечать на callback быстро (до таймаута) и возвращать 2xx.
Обработку события делай асинхронной, если она долгая.

## Rate limit

100 запросов в минуту на интеграцию (по client_id из JWT).
При превышении — HTTP 429. Используй exponential backoff при получении 429.

## Коды ошибок

Тело ошибки HTTP API: { "errorCode": <int>, "errorDescription": "<string>" }
У OAuth2-сервера другой формат: error / error_description (см. аутентификацию выше).

| HTTP | Значение |
|------|----------------------------------------------------|
| 400 | Неверный запрос / неверное состояние webhook |
| 401 | Токен отсутствует или невалиден |
| 403 | Недостаточно прав (нет нужного scope) |
| 404 | Интеграция не найдена или отключена |
| 409 | Конфликт параллельных изменений webhook |
| 429 | Rate limit превышен — нужно сделать паузу |
| 500 | Ошибка сервера — состояние доставки не определено |
| 503 | Сервис недоступен — состояние доставки не определено|

## Рекомендуемая retry-логика

- 4xx (кроме 429) — не ретраить, это ошибка запроса
- 429 — подождать и повторить (exponential backoff)
- 500/503 — ретраить только если передан externalId (идемпотентный запрос)
- Таймаут соединения — ретраить с externalId

Помогай разработчику писать код с учётом всех этих правил.
Если спрашивают про язык — пиши на указанном языке.
Если язык не указан — уточни или предложи Python как базовый пример.