Для AI-агентов: markdown этой страницы — /docs/identifiers-and-pagination.mdиндекс документации — /llms.txt
Идентификаторы и страницы результатов
Обновлено
Сохраняйте номер объекта вместе с бизнесом, которому он принадлежит. Для управления используйте номер из ответа защищённого API, для передачи публичной ссылки — выданный непрозрачный код. Номер объекта не даёт права его читать.
TelegaFirst — AI-фронт-офис в Telegram для микробизнеса. Владелец и операторы работают в Telegram; свой AI-агент клиента управляет доступным бизнесом через scoped Hub. Покупатель обращается к бизнесу через поддерживаемый канал и имеет отдельные права на свои объекты. Авторизация и scopes определяют доступ до разрешения адреса.
Четыре вида адреса
| Поверхность | Адрес | Что разрешает доступ |
|---|---|---|
| P1: публичная ссылка | Непрозрачный UniversalLink.code; единственная читаемая строка бизнеса — Client.slug | Предусмотренный публичный адрес; разрешение учитывает бизнес из хоста |
| P2: кабинет покупателя | Номер seq_num внутри бизнеса | Customer session и проверка принадлежности объекта покупателю |
| P3: управление бизнесом, CRM, Hub, MCP | Номер внутри бизнеса и название для человека | Credential, доступный бизнес, scopes и актуальные полномочия |
| P4: внутренняя база | Внутренний первичный ключ | Используется платформой и не передаётся через публичный периметр |
Название поля зависит от контракта: каталог и пользователи используют seq_id, заказы и ответы форм — seq_num, записи booking — seqNum. Не переименовывайте их самостоятельно. Номера разных видов объектов и разных бизнесов могут совпадать. В Hub объект разрешается по бизнесу из проверенного контекста и его номеру; в кабинете покупателя дополнительно проверяется владелец объекта. Подстановка другого номера или client_id в тело не расширяет доступ.
В P1 код разрешается вместе с бизнесом, определённым хостом. Для карточки товара используется /product/{code}, для формы — /f/{code}. Не заменяйте код номером и не создавайте отдельные читаемые slug товара, формы или события. Зоны .ru и .com поддерживаются обе; зона определяет соответствующий рынок и платёжные требования. Показанные ниже значения — контрактные иллюстрации, а не действующие публичные ссылки.
Один товар может одновременно иметь P3 seq_id: 7 и отдельный deeplink_code: "ProductCode12345". Первое значение подходит для защищённого чтения или изменения каталога, второе — для предусмотренной публичной ссылки. Имя route-параметра id само по себе не означает внутренний PK: например, защищённый /api/v1/orders/{id} принимает номер заказа внутри бизнеса.
Ответ формы имеет собственный номер
form_seq_num указывает на форму. seq_num указывает на конкретный ответ этой формы. form_title хранит название формы на момент ответа и не служит адресом. submission_code — отдельный публичный код существующего реестра ссылок.
Каждый успешно сохранённый ответ получает номер при создании, включая status: "anonymous". Аутентифицированный Hub caller не устанавливает личность посетителя: анонимный ответ уже имеет номер, но ещё не связан с покупателем. Привязка к пользователю сохраняет номер и код. Повтор принятого запроса с его ключом также сохраняет идентичность ответа. Для старых ответов без номера перенос выделяет недостающие номера, сохраняя ранее выданные номера и публичные коды; клиенту не нужно пересоздавать объекты или заменять ссылки.
Номер ответа — положительное целое от 1 до 2147483647. P3 операции над ним используют этот номер в контексте бизнеса. Публичный код не является альтернативным P3 параметром. В контракте ответа linked_user_seq_num появляется при подтверждённой связи с пользователем; внутреннего user_id нет. Полный payload при чтении отсутствует по умолчанию: явный include: "full_payload" требует предусмотренного доступа и записывает аудит. Название и номер не отменяют защиту персональных данных.
Пример: принять ответ формы через Hub
Результат — сохранённый анонимный ответ с собственным номером. Нужны действующий Hub credential с push:form_submissions, доступный бизнес, разрешённый data plane и форма №12 с декларацией, принимающей поле email. <HUB_BASE_URL> — адрес выданного вам Hub без завершающего /; <API_KEY> — локальный секрет. Значения из примера не подтверждают готовность конкретного сервера. Не вставляйте credential или реальные ответы покупателей в промпт.
POST <HUB_BASE_URL>/api/v1/form-submissions HTTP/1.1
X-Api-Key: <API_KEY>
Content-Type: application/json
Idempotency-Key: form-1042
{"form_seq_num":12,"payload":{"email":"ada@example.test"}}Успех, HTTP 202:
{"outcome":"accepted","seq_num":1042,"submission_code":"opaque-form-answer","status":"anonymous"}Здесь форма №12 и ответ №1042 — разные P3 объекты. Код показан отдельно и не заменяет номер. При потерянном ответе повторите тот же REST-запрос с тем же ключом в его окне replay; новое тело требует нового ключа. MCP submit_form_submission не обещает дедупликацию двух новых вызовов: каждый новый submit создаёт новый ответ. Для P3 чтения и обработки используйте фактически доступные MCP операции форм; REST-контроллер этого семейства предоставляет POST, а выдуманные GET/detail/mark маршруты использовать нельзя. Формы и сайт, повтор запросов.
| Отказ | Действие |
|---|---|
401 INVALID_API_KEY | Проверить credential и endpoint; авторизация |
403 INSUFFICIENT_SCOPE | Проверить push:form_submissions, актуальные права, план и платное окно |
400 IDEMPOTENCY_KEY_REQUIRED | Передать ключ запроса |
422 IDEMPOTENCY_KEY_MISMATCH | Не менять тело принятого запроса под тем же ключом |
409 CONFLICT | Предыдущий запрос с этим ключом ещё выполняется; дождаться результата |
429 RATE_LIMIT_EXCEEDED | Выдержать Retry-After, если он указан |
Форма дополнительно проверяет объявленную schema, доступность и принадлежность бизнесу. HTTP 202 не означает, что посетитель установлен или оператор обработал ответ. Для диагностики сохраните фактический код и traceId без payload. Справочник ошибок.
Pull pagination: возвращайте cursor без изменений
Pull списки пользователей, платежей, заказов и ответов форм возвращают success, массив data и meta с has_more, next_cursor, limit; estimated_total может отсутствовать. Размер страницы — от 1 до 200, по умолчанию 50 для общей Pull query. Конкретная операция может задавать более узкие ограничения; используйте её schema.
Для этих четырёх Pull ресурсов cursor — зашифрованный аутентифицированный токен AES-GCM со сроком 900 секунд от выдачи. Он связан с текущим бизнесом, видом ресурса и эффективными нормализованными фильтрами. Версия ключа находится в токене, например префикс v1a; это не номер страницы и не адрес объекта. Старый plaintext/base64 cursor, повреждённый токен, неизвестная версия ключа, истёкший cursor и перенос токена в другой бизнес, ресурс или фильтр дают HTTP 400 INVALID_CURSOR. Клиенту нельзя декодировать, собирать или исправлять токен.
Выполните первый запрос без cursor с нужными фильтрами.
Обработайте
data. Еслиhas_more: true, возьмите точную строкуmeta.next_cursor.Повторите запрос к тому же ресурсу и бизнесу с теми же фильтрами, передав строку cursor как URL-encoded query-параметр.
При
has_more: falseиnext_cursor: nullостановитесь. ПриINVALID_CURSORначните новую выборку без старого токена; не снимайте фильтры, чтобы «починить» его.
Cursor задаёт позицию keyset-выборки, а не неизменный снимок всех данных. estimated_total — оценка, не условие окончания обхода. После смены активного бизнеса начинайте отдельный обход. Выбор бизнеса.
Пример: заказы пользователя №7
Нужны pull:orders, доступ к бизнесу и открытый для данных план/платное окно. API key и предусмотренный Bearer credential проходят собственную проверку. Фильтр user_seq_num — P3 номер пользователя, не внутренний PK. Для одного номера используется scalar; поддерживаемый IN-фильтр также принимает только положительные int4 номера. Старый user_id для этой выборки не принимается.
GET <HUB_BASE_URL>/api/v1/orders?limit=2&user_seq_num=7 HTTP/1.1
X-Api-Key: <API_KEY>Полный контрактный ответ, HTTP 200:
{
"success": true,
"data": [{
"seq_num": 71,
"status": "pending",
"amount": "0",
"currency": "RUB",
"external_order_ref": "crm-71",
"created_at": "2026-09-30T12:00:00.000Z",
"updated_at": "2026-10-01T12:00:00.000Z"
}],
"meta": {"has_more":false,"next_cursor":null,"limit":2,"estimated_total":1}
}Этот пример заканчивается одной страницей. Если ваш реальный ответ имеет следующую страницу, передайте его токен в cursor, сохранив user_seq_num=7. Не используйте примерный токен из другого запуска. Внешний external_order_ref — ссылка вашей интеграции, а не PK платформы.
Пример отказа при неверном номере пользователя, HTTP 400, Content-Type: application/problem+json:
{
"type":"https://telegafirst.ru/docs/errors#INVALID_FILTER",
"title":"Bad Request",
"status":400,
"instance":"/api/v1/orders",
"code":"INVALID_FILTER",
"traceId":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"detail":"user_seq_num must be a positive int4 number"
}| Отказ Pull запроса | Действие |
|---|---|
400 INVALID_CURSOR | Начать выборку заново с тем же бизнесом и фильтрами |
400 INVALID_FILTER | Исправить имя, вид или пределы фильтра |
400 INVALID_REQUEST | Проверить размер страницы по schema операции |
401 / 403 | Проверить credential, scopes и текущий доступ; cursor их не заменяет |
Каталог имеет отдельный протокол страниц
GET /api/v1/catalog требует catalog:read, принимает zone: ru|com, limit от 1 до 100 с default50 и собственный cursor. Его ответ также содержит meta.next_cursor, но этот cursor кодирует публичный номер каталога и не имеет описанного выше encrypted900-second Pull протокола. В контрактном примере cursor=Ng&limit=1&zone=ru возвращает товар seq_id:7 и next_cursor:"Nw". Используйте возвращённую строку; не переносите токены между ресурсами и не принимайте её за внутренний PK. Списки событий и booking также имеют собственные schemas: универсальный формат всем спискам не навязывается.
Для чтения одного товара и его версии используйте GET /api/v1/catalog/7?zone=ru; после него — ETag и идемпотентность. Каталог и продажи описывает дальнейшие операции. Scopes, название credential и число в URL никогда не заменяют проверку доступного бизнеса.