Api

HTTP API v3

Чаты, сообщения, вложения и базы знаний через REST /api/v3 — с примерами на Python и TypeScript.

Ниже — HTTP API версии v3: отдельный набор маршрутов с префиксом /api/v3/…. Он рассчитан на чаты с версией v3 (история в виде цепочки «run items»), генерацию ответов и работу с вложениями.

Замените BASE_URL на адрес вашего окружения (например, https://api.er-gpt.ru). Токен — тот же способ входа, что и для остального API портала (заголовок Authorization: Bearer …).

Зачем версия чата v3

  • У каждого чата есть версия (v2 или v3). Для v3 история и генерация идут через эндпоинты /api/v3/….
  • Если вызвать v3 для чата другой версии, API вернёт ошибку и подскажет, какой префикс использовать.
  • POST /api/v3/chat всегда создаёт чат версии v3.

Обзор маршрутов

ПрефиксНазначение
/api/v3/messageИстория чата и генерация ответа (в т.ч. one-shot без сохранённого чата)
/api/v3/chatСписок и настройка чатов, избранное, вложения в контексте чата
/api/v3/attachmentЗагрузка файла и список ваших вложений
/api/v3/knowledgeТо же, что /api/knowledge: базы знаний, документы, поиск (удобный дубль префикса)

Сообщения

Получить историю — GET /api/v3/message

История чата v3 — постраничная выдача элементов run (result) и курсор в pagination.

Параметры запроса

Endpoint: GET https://api.er-gpt.ru/api/v3/message

chat_id
uuid required
Идентификатор чата.
limit
integer
Размер страницы (сколько элементов за запрос). По умолчанию 50.
cursor
string (opaque)
Курсор следующей страницы: значение из pagination.cursor предыдущего ответа. При первом запросе не передаётся.

Ответ

Тело ответа — JSON с полями result (массив строк истории) и pagination (в т.ч. следующий cursor).

result
array
Элементы истории (поля одного элемента — ниже).
pagination.cursor
string | null
Курсор для следующего GET или null, если страниц больше нет.
pagination.limit
integer
Тот же лимит, что в запросе.

Поля одного элемента result[]

run_id
string
Идентификатор run.
sequence_number
integer
Порядковый номер элемента внутри run.
item_type
string
Дублирует типичное поле type из item, если оно есть (удобно для списков без разбора JSON).
item_status
string | null
Дублирует типичное поле status из item, если оно есть.
item
object
Полезная нагрузка шага: пользовательское сообщение или элемент output Responses API (см. ниже).
chat_id
uuid
Идентификатор чата.
run_completed_at
string (ISO 8601)
Время завершения run.

Содержимое item

  1. Вход пользователя / системы: type: "message", roleuser | system | developer, массив content в формате частей OpenAI Responses (input_text, input_image и т.д.). Встроенные id сообщений OpenAI в этих строках могут отсутствовать.
  2. Вывод модели: те же объекты, что в массиве output завершённого ответа Responses API (ответ ассистента, function_call, reasoning, file_search_call и др. — см. Response output items в документации OpenAI).

В TypeScript удобно сочетать типы пакета openai (ResponseOutputItem и смежные) с узким интерфейсом для пользовательского type: "message".

Примеры реализации

Ниже — разнесение по файлам: модели, метод с httpx / axios, точка входа (как на странице Одиночные запросы).

main.py
import logging
import os

import httpx

from methods import fetch_message_history

logging.basicConfig(level=logging.INFO)

BASE_URL = os.getenv("API_BASE_URL", "https://api.er-gpt.ru")
API_TOKEN = os.getenv("API_TOKEN")
CHAT_ID = os.getenv("CHAT_ID", "00000000-0000-4000-8000-000000000000")


def main() -> None:
    if not API_TOKEN:
        return
    headers = {"Authorization": f"Bearer {API_TOKEN}"}
    with httpx.Client(base_url=BASE_URL, headers=headers, timeout=60.0) as client:
        page = fetch_message_history(client, chat_id=CHAT_ID, limit=50)
        if page:
            for row in page["result"]:
                item = row.get("item") or {}
                print(row["item_type"], row.get("item_status"), item.get("type"))


if __name__ == "__main__":
    main()

Сгенерировать ответ в чате — POST /api/v3/message/generate

Один URL: в теле запроса поле stream выбирает формат ответа.

Обязательный заголовок: Idempotency-Key — любая уникальная строка на один пользовательский «ход» (UUID подойдёт). Повтор с тем же ключом не создаст дубликат того же шага.

Тело (основное)

ПолеСмысл
streamfalse — один JSON с готовым ответом; true — поток SSE
chat_id, assistant_id, model_idЧат, ассистент и модель из каталога
inputСтрока или массив элементов в формате OpenAI Responses (входные сообщения и медиа)
parent_idНеобязательно — связь с предыдущим run
thinkВключить размышления модели (отдельные фрагменты в потоке, если модель их поддерживает); флаг think
ragСм. раздел RAG ниже
include_tools / exclude_toolsОграничить список инструментов (нельзя указать оба сразу)
max_tokens, temperature, top_p, presence_penaltyПараметры генерации

При stream: false в ответе приходит JSON финального объекта (как поле response у события response.completed в потоке ниже). При stream: true тело ответа — SSE (Content-Type: text/event-stream): блоки вида event: <имя_события> + одна или несколько строк data: с JSON, затем пустая строка. Имена событий и структура JSON в data совпадают с потоковыми событиями OpenAI Responses API (тот же контракт, что у типа ResponseStreamEvent в официальных SDK: response.created, response.output_text.delta, response.reasoning_text.delta, response.output_item.added, response.completed и т.д.). На стороне сервера эти события собираются из типов openai.types.responses.*, поэтому удобнее всего читать поток официальным клиентом OpenAI с base_url на хост ERGPT и низкоуровневым post(..., stream=True) — ниже примеры для Python и Node.

import uuid
import httpx

BASE_URL = "https://api.er-gpt.ru"
TOKEN = "ВАШ_ТОКЕН"
CHAT_ID = "00000000-0000-4000-8000-000000000001"
ASSISTANT_ID = "00000000-0000-4000-8000-000000000002"
MODEL_ID = "имя-модели-из-каталога"

payload = {
    "stream": False,
    "chat_id": CHAT_ID,
    "assistant_id": ASSISTANT_ID,
    "model_id": MODEL_ID,
    "input": "Кратко объясни, что такое RAG.",
    "rag": False,
}

r = httpx.post(
    f"{BASE_URL}/api/v3/message/generate",
    json=payload,
    headers={
        "Authorization": f"Bearer {TOKEN}",
        "Idempotency-Key": str(uuid.uuid4()),
        "Content-Type": "application/json",
    },
    timeout=120.0,
)
r.raise_for_status()
print(r.json())

Поток SSE (stream: true)

Зависимости: Python — pip install "openai>=1.76" (лучше актуальную ветку 2.x, как в нашем бэкенде); Node — npm install openai. Укажите base_url / baseURL без суффикса /v1 (например https://api.er-gpt.ru), иначе клиент по умолчанию ходит на api.openai.com/v1.

Используется низкоуровневый post: тот же разбор SSE и типизация событий, что и у стрима responses.create у OpenAI, но путь и тело запроса — наши (/api/v3/message/generate). Для one-shot с stream: true всё то же самое, путь /api/v3/message/one-shot, заголовок Idempotency-Key не нужен.

import uuid
from openai import OpenAI, Stream
from openai.types.responses.response_stream_event import ResponseStreamEvent

BASE_URL = "https://api.er-gpt.ru"
TOKEN = "ВАШ_ТОКЕН"

payload = {
    "stream": True,
    "chat_id": "00000000-0000-4000-8000-000000000001",
    "assistant_id": "00000000-0000-4000-8000-000000000002",
    "model_id": "имя-модели-из-каталога",
    "input": "Привет!",
}

client = OpenAI(api_key=TOKEN, base_url=BASE_URL, timeout=120.0)

stream = client.post(
    "/api/v3/message/generate",
    cast_to=ResponseStreamEvent,
    body=payload,
    stream=True,
    stream_cls=Stream[ResponseStreamEvent],
    options={"headers": {"Idempotency-Key": str(uuid.uuid4())}},
)

with stream:
    for event in stream:
        if event.type == "response.output_text.delta":
            print(event.delta, end="", flush=True)
        elif event.type == "response.reasoning_text.delta":
            print(event.delta, end="", flush=True)
        elif event.type == "response.completed":
            print("\n--- done ---")
            break

One-shot — POST /api/v3/message/one-shot

Один запрос без сохранённого чата: подходит для разовых ответов. Поле stream работает так же, как у генерации в чате. Заголовок Idempotency-Key не нужен.

Кратко по полям:

  • input или устаревшее content — текст пользователя.
  • runs — необязательно: можно передать «накопленную» историю в виде массива объектов с полями вроде id и output.
  • assistant_id: null (кастомный или универсальный сценарий по полю assistant), строка "searcher" (режим «поиск по базе» с опциональным kb_id), либо UUID ассистента из каталога.
  • rag по умолчанию "agent" (см. RAG).
import httpx

BASE_URL = "https://api.er-gpt.ru"
TOKEN = "ВАШ_ТОКЕН"

payload = {
    "stream": False,
    "model_id": "имя-модели-из-каталога",
    "input": "Суммируй в двух предложениях: что такое embeddings.",
    "assistant_id": None,
    "rag": "agent",
}

r = httpx.post(
    f"{BASE_URL}/api/v3/message/one-shot",
    json=payload,
    headers={"Authorization": f"Bearer {TOKEN}"},
    timeout=120.0,
)
r.raise_for_status()
print(r.json())

Чаты — /api/v3/chat

МетодПутьНазначение
GET/api/v3/chatСписок чатов (search, limit, cursor, exclude_favorites)
POST/api/v3/chatСоздать чат (тело — имя и др.; версия будет v3)
GET/api/v3/chat/favoriteИзбранные чаты
GET/api/v3/chat/{chat_id}Получить чат
PATCH/api/v3/chat/{chat_id}Обновить
DELETE/api/v3/chat/{chat_id}Удалить
POST/api/v3/chat/{chat_id}/generate-nameСгенерировать название
GET/api/v3/chat/{chat_id}/attachmentsВложения чата (поиск по имени файла — query search)
POST / DELETE/api/v3/chat/{chat_id}/favoriteВ избранное / из избранного
import httpx

BASE_URL = "https://api.er-gpt.ru"
TOKEN = "ВАШ_ТОКЕН"

r = httpx.post(
    f"{BASE_URL}/api/v3/chat",
    json={"name": "Мой чат v3"},
    headers={"Authorization": f"Bearer {TOKEN}"},
    timeout=30.0,
)
r.raise_for_status()
print(r.json())

Вложения — /api/v3/attachment

Список — GET /api/v3/attachment

Параметры: chat_id (необязательно — тогда все ваши вложения или только по чату), search, limit, cursor.

Загрузка — POST /api/v3/attachment

Один файл, multipart/form-data, поле с файлом (как принимает ваш клиент — часто имя поля file).

import httpx

BASE_URL = "https://api.er-gpt.ru"
TOKEN = "ВАШ_ТОКЕН"

with open("notes.txt", "rb") as f:
    r = httpx.post(
        f"{BASE_URL}/api/v3/attachment",
        headers={"Authorization": f"Bearer {TOKEN}"},
        files={"file": ("notes.txt", f, "text/plain")},
        timeout=120.0,
    )
    r.raise_for_status()
    print(r.json())

Базы знаний — /api/v3/knowledge

Поведение совпадает с /api/knowledge: список баз, загрузка документов, поиск по базе и т.д. Удобно использовать тот префикс, который совпадает с остальными v3-вызовами в вашем коде.


RAG: поиск по базе

Поле rag в теле генерации (чат или one-shot) задаёт, как подмешиваются знания ассистента:

ЗначениеПоведение
falseАвтоматический поиск по базе до ответа модели не выполняется.
trueЕсли у ассистента привязана база знаний, сервер сам выполняет поиск и подставляет найденное в контекст (как заранее выполненный шаг инструмента поиска по базе).
"agent"Автоматического пред-поиска нет: модель опирается на свои инструменты и настройки ассистента.
объект с полями threshold, search_type (hybrid, dense, sparse), limit, rerank, summary_modeТо же, что true, но с переопределением параметров поиска.

У сценария one-shot по умолчанию стоит "agent"; у генерации в чате по умолчанию false.


Что смотреть дальше

  • Полные схемы запросов и ответов — в Swagger вашего стенда.
  • Формат входа input как у OpenAI Responses и имена событий в SSE — в документации OpenAI по Responses API; отдельная страница про OpenAI-совместимость у нас — OpenAI-совместимый API.
Copyright © 2026