RUcodex APIOPENAI-СОВМЕСТИМЫЙ ИНТЕРФЕЙС Войти
Меняются только адрес и ключ

От первого запроса
до готового AI-приложения.

Полное руководство по RUcodex API: как вести диалог без потери контекста, показывать ответ по мере генерации, вызывать функции вашего приложения, анализировать и создавать изображения.

OpenAI SDK Диалоги с памятью Streaming SSE Tools и изображения
Продолжение диалогаCHAT COMPLETIONS
// 1. Храните историю у себя
messages = [
  { role: "system", content: "Ты помощник" },
  { role: "user", content: "Меня зовут Анна" }
]

// 2. Добавьте ответ AI
messages.push(response.choices[0].message)

// 3. Добавьте следующий вопрос
messages.push({
  role: "user",
  content: "Как меня зовут?"
})

// 4. Отправьте весь messages снова
Контекст принадлежит вашему приложению и не теряется
BASE URL OPENAIhttps://api.openai.com/v1
BASE URL RUCODEXhttps://rucodex.ru/v1
СОДЕРЖАНИЕ

От подключения до production

Читайте последовательно или сразу переходите к нужному сценарию. В каждом разделе есть готовые запросы и пояснение структуры ответа.

ЛИЧНЫЙ КАБИНЕТ API

Ключи доступа

Создать ключ можно сразу после регистрации. Без тарифа он работает с бесплатной моделью rucodex-test, а после оплаты автоматически получает доступ к моделям подписки.

Проверяем авторизацию…
ЗАГОЛОВОКAuthorization: Bearer rucodex_sk_...

Ключ передаётся в каждом запросе. Префикс Bearer обязателен.

СЕКРЕТRUCODEX_API_KEY

Храните ключ в переменной окружения на сервере. Не вставляйте его в браузерный JavaScript.

МОДЕЛИGET /v1/models

Получайте доступный каталог программно: набор моделей меняется вместе с тарифом.

БЫСТРЫЙ СТАРТ

Первый запрос и первый ответ

Выберите привычный инструмент. Для бесплатной проверки используйте rucodex-test; при активной подписке — идентификатор из GET /v1/models.

cURL · Chat Completions
1

Создайте ключ

Полное значение показывается один раз. Сохраните его как секрет.

2

Получите модели

Вызовите GET /v1/models и используйте точное значение поля id.

3

Прочитайте ответ

Для Chat Completions текст находится в choices[0].message.content.

ЗАПРОС

Узнать доступные модели

curl https://rucodex.ru/v1/models \
  -H "Authorization: Bearer $RUCODEX_API_KEY"

Не храните список моделей навсегда в коде. Показывайте пользователю поле id из ответа.

ОТВЕТ

Где находится текст

{
  "id": "chatcmpl_...",
  "choices": [{
    "message": {
      "role": "assistant",
      "content": "Готовый ответ AI"
    },
    "finish_reason": "stop"
  }],
  "usage": {
    "prompt_tokens": 24,
    "completion_tokens": 86,
    "total_tokens": 110
  }
}
choices[0].message.contentТекст, который нужно показать пользователю.
finish_reasonstop — ответ закончен; length — достигнут лимит длины; tool_calls — модель запросила функцию.
usageКоличество токенов запроса и ответа, если их вернул основной API.
idИдентификатор запроса; сохраняйте его в журнале для диагностики.
ДИАЛОГ И КОНТЕКСТ

Как сделать так, чтобы AI не забывал

Каждый API-запрос сам по себе независим. Для Chat Completions ваше приложение хранит историю и отправляет её заново при каждом сообщении.

Главное правило

После ответа добавьте объект assistant в историю, затем добавьте новое сообщение user и отправьте весь массив messages. Одного текста последнего вопроса недостаточно.

1Пользователь

Добавьте вопрос с ролью user

2RUcodex API

Получите объект assistant

3Ваша база

Сохраните оба сообщения

4Новый вопрос

Отправьте всю историю снова

PHP 8.3 · ПОЛНЫЙ ПРИМЕР

Диалог с памятью в сессии

<?php
session_start();

$apiKey = getenv('RUCODEX_API_KEY');
$model = 'gpt-5.6-terra'; // Возьмите id из GET /v1/models
$question = trim($_POST['message'] ?? '');

// В production храните историю по user_id + chat_id в MySQL.
$_SESSION['messages'] ??= [
    ['role' => 'system', 'content' => 'Ты полезный помощник. Отвечай по-русски.'],
];
$_SESSION['messages'][] = ['role' => 'user', 'content' => $question];

$curl = curl_init('https://rucodex.ru/v1/chat/completions');
curl_setopt_array($curl, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'model' => $model,
        'messages' => $_SESSION['messages'],
    ], JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR),
    CURLOPT_TIMEOUT => 120,
]);

$raw = curl_exec($curl);
if ($raw === false) throw new RuntimeException(curl_error($curl));
$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);

$data = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);
if ($status >= 400) {
    // Последний вопрос не получил ответа — убираем его из истории.
    array_pop($_SESSION['messages']);
    throw new RuntimeException($data['error']['message'] ?? "HTTP $status");
}

$assistant = $data['choices'][0]['message'];
$_SESSION['messages'][] = $assistant; // Без этого AI забудет свой ответ.

header('Content-Type: application/json; charset=utf-8');
echo json_encode(['answer' => $assistant['content']], JSON_UNESCAPED_UNICODE);
ИСТОРИЯ ВТОРОГО ЗАПРОСА

Как выглядит messages

"messages": [
  {
    "role": "system",
    "content": "Ты финансовый помощник"
  },
  {
    "role": "user",
    "content": "Мой бюджет — 80 000 ₽"
  },
  {
    "role": "assistant",
    "content": "Зафиксировал бюджет"
  },
  {
    "role": "user",
    "content": "Предложи распределение"
  }
]
РОЛИ

Кто что говорит

system
Правила поведения, язык, формат и ограничения. Обычно первое сообщение.
user
Сообщение человека или данные, которые он передал приложению.
assistant
Полный ответ AI. Его обязательно сохраняют для продолжения разговора.
tool
Результат функции вашего сервера, связанный с конкретным tool_call_id.

Как хранить длинные диалоги

Разделяйте чаты. Храните сообщения по паре user_id + chat_id, чтобы контекст разных диалогов не смешивался.

Сохраняйте порядок. Записывайте роль, content, tool_calls и время каждого сообщения.

Контролируйте размер. Когда история становится большой, суммируйте старую часть отдельным запросом и оставляйте резюме плюс последние сообщения.

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

RESPONSES API

Современный способ работать с AI

Responses API объединяет текст, изображения и инструменты в одном интерфейсе. RUcodex передаёт его параметры и ответ в OpenAI-совместимом формате.

ПЕРВЫЙ ОТВЕТ

Python и официальный SDK

from openai import OpenAI

client = OpenAI(
    api_key="rucodex_sk_...",
    base_url="https://rucodex.ru/v1"
)

response = client.responses.create(
    model="gpt-5.6-terra",
    instructions="Отвечай кратко и по-русски",
    input="Придумай название для IT-сервиса"
)

print(response.output_text)
print(response.id)  # Сохраните для продолжения
ПРОДОЛЖЕНИЕ

Через previous_response_id

next_response = client.responses.create(
    model="gpt-5.6-terra",
    previous_response_id=response.id,
    instructions="Отвечай кратко и по-русски",
    input="Предложи ещё пять вариантов"
)

print(next_response.output_text)

previous_response_id связывает новый ответ с предыдущим. Сохраните ID рядом с вашим chat_id. Постоянные правила из instructions безопаснее передавать снова.

Совместимый запасной вариант

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

response.output_textУдобное свойство SDK, объединяющее текстовые части ответа.
response.outputПолный список элементов: сообщения, tool calls и другие типы результата.
response.idИдентификатор, который можно использовать как previous_response_id.
response.statusСостояние выполнения; перед показом результата проверяйте успешное завершение.
STREAMING SSE

Показывайте ответ сразу, слово за словом

Передайте stream: true. Сервер вернёт поток событий data:; текст приходит частями в choices[0].delta.content, а маркер [DONE] завершает поток.

data: { "choices": [{ "delta": { "content": "Привет" } }] }data: { "choices": [{ "delta": { "content": "!" } }] }data: [DONE]
PYTHON

OpenAI SDK

stream = client.chat.completions.create(
    model="gpt-5.6-terra",
    messages=[
        {"role": "user", "content": "Объясни SSE"}
    ],
    stream=True
)

answer = ""
for chunk in stream:
    delta = chunk.choices[0].delta.content or ""
    answer += delta
    print(delta, end="", flush=True)

# Сохраните answer как сообщение assistant
NODE.JS

OpenAI SDK

const stream = await client.chat.completions.create({
  model: "gpt-5.6-terra",
  messages: [
    { role: "user", content: "Объясни SSE" }
  ],
  stream: true
});

let answer = "";
for await (const chunk of stream) {
  const delta = chunk.choices[0]?.delta?.content ?? "";
  answer += delta;
  process.stdout.write(delta);
}

// Сохраните answer в истории диалога
PHP 8.3

Чтение SSE

$payload = json_encode([
    'model' => 'gpt-5.6-terra',
    'messages' => [
        ['role' => 'user', 'content' => 'Объясни SSE'],
    ],
    'stream' => true,
], JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);

$curl = curl_init('https://rucodex.ru/v1/chat/completions');
curl_setopt_array($curl, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('RUCODEX_API_KEY'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => $payload,
    CURLOPT_TIMEOUT => 120,
]);

$buffer = '';
$answer = '';
curl_setopt($curl, CURLOPT_WRITEFUNCTION,
    function ($curl, string $chunk) use (&$buffer, &$answer) {
        $buffer .= $chunk;
        while (($pos = strpos($buffer, "\n")) !== false) {
            $line = trim(substr($buffer, 0, $pos));
            $buffer = substr($buffer, $pos + 1);
            if (!str_starts_with($line, 'data:')) continue;
            $data = trim(substr($line, 5));
            if ($data === '[DONE]') continue;
            $event = json_decode($data, true);
            $delta = $event['choices'][0]['delta']['content'] ?? '';
            $answer .= $delta;
            echo $delta;
            flush();
        }
        return strlen($chunk);
    }
);

$ok = curl_exec($curl);
if ($ok === false) throw new RuntimeException(curl_error($curl));
$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);
if ($status >= 400) throw new RuntimeException("HTTP $status");

// После [DONE] сохраните $answer как сообщение assistant.

Правила потокового режима

Сначала добавьте вопрос пользователя в историю, но ответ assistant сохраняйте только после завершения потока.

Если соединение оборвалось, пометьте ответ как незавершённый и предложите пользователю повторить запрос.

Отключите буферизацию у своего reverse proxy и отправляйте данные браузеру сразу.

До начала SSE сервер может вернуть обычный JSON с ошибкой — проверяйте HTTP-статус.

FUNCTION CALLING / TOOLS

AI решает, ваша программа выполняет

Модель не вызывает вашу функцию самостоятельно. Она возвращает имя и аргументы; ваш сервер проверяет их, выполняет действие и отправляет результат обратно.

01

Передайте описание функции в tools

02

Прочитайте message.tool_calls

03

Проверьте аргументы и выполните свой код

04

Отправьте роль tool и получите финальный текст

PYTHON · ПОЛНЫЙ ЦИКЛ

Функция получения статуса заказа

import json
from openai import OpenAI

client = OpenAI(api_key="rucodex_sk_...", base_url="https://rucodex.ru/v1")

tools = [{
    "type": "function",
    "function": {
        "name": "get_order_status",
        "description": "Возвращает статус заказа по его номеру",
        "parameters": {
            "type": "object",
            "properties": {
                "order_id": {"type": "string", "description": "Номер, например A-1042"}
            },
            "required": ["order_id"],
            "additionalProperties": False
        }
    }
}]

messages = [{"role": "user", "content": "Где мой заказ A-1042?"}]
first = client.chat.completions.create(
    model="gpt-5.6-terra",
    messages=messages,
    tools=tools
)

assistant_message = first.choices[0].message
messages.append(assistant_message)  # Сохраняем tool_calls целиком

for call in assistant_message.tool_calls or []:
    if call.function.name != "get_order_status":
        raise ValueError("Неизвестная функция")

    args = json.loads(call.function.arguments)
    order_id = args["order_id"]

    # Здесь выполняется ваш код: запрос к БД, CRM или внешнему API.
    function_result = {"order_id": order_id, "status": "Передан курьеру"}

    messages.append({
        "role": "tool",
        "tool_call_id": call.id,
        "content": json.dumps(function_result, ensure_ascii=False)
    })

final = client.chat.completions.create(
    model="gpt-5.6-terra",
    messages=messages,
    tools=tools
)

print(final.choices[0].message.content)
Безопасность tools

Считайте аргументы модели недоверенными данными. Разрешайте только известные функции, валидируйте типы и права пользователя, ограничивайте суммы и никогда не выполняйте полученную строку как SQL, PHP или shell-команду.

ИЗОБРАЖЕНИЯ

Создать, получить, сохранить и отредактировать

Генерация выполняется через POST /v1/images/generations. В зависимости от модели результат содержит временный url или строку b64_json.

ГЕНЕРАЦИЯ

Запрос cURL

curl https://rucodex.ru/v1/images/generations \
  -H "Authorization: Bearer $RUCODEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "MODEL_ID_FROM_V1_MODELS",
    "prompt": "Современный рабочий стол программиста, мягкий свет",
    "size": "1024x1024",
    "n": 1
  }'

Доступные значения size, качество и поддержка прозрачности зависят от выбранной модели.

ФОРМАТ ОТВЕТА

URL или base64

{
  "created": 1786150800,
  "data": [{
    "url": "https://.../temporary-image.png",
    "b64_json": null,
    "revised_prompt": "Уточнённое описание..."
  }]
}

Проверяйте оба поля. Если пришёл URL — скачайте файл сразу: ссылка может быть временной. Если пришёл b64_json — декодируйте его в бинарный файл.

PHP 8.3 · ПОЛУЧЕНИЕ ФАЙЛА

Обработка URL и base64 одним кодом

<?php
$result = json_decode($rawApiResponse, true, 512, JSON_THROW_ON_ERROR);
$image = $result['data'][0] ?? null;
if (!$image) throw new RuntimeException('API не вернул изображение');

$target = __DIR__ . '/generated/' . bin2hex(random_bytes(12)) . '.png';

if (!empty($image['b64_json'])) {
    $binary = base64_decode($image['b64_json'], true);
    if ($binary === false) throw new RuntimeException('Некорректный base64');
} elseif (!empty($image['url'])) {
    $download = curl_init($image['url']);
    curl_setopt_array($download, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_TIMEOUT => 60,
        CURLOPT_MAXREDIRS => 3,
    ]);
    $binary = curl_exec($download);
    if ($binary === false) throw new RuntimeException(curl_error($download));
    $status = curl_getinfo($download, CURLINFO_RESPONSE_CODE);
    curl_close($download);
    if ($status < 200 || $status >= 300) throw new RuntimeException("Download HTTP $status");
} else {
    throw new RuntimeException('В ответе нет url или b64_json');
}

// Перед записью создайте каталог и запретите в нём выполнение скриптов.
if (file_put_contents($target, $binary, LOCK_EX) === false) {
    throw new RuntimeException('Не удалось сохранить изображение');
}

echo basename($target);
РЕДАКТИРОВАНИЕ

Multipart-запрос

curl https://rucodex.ru/v1/images/edits \
  -H "Authorization: Bearer $RUCODEX_API_KEY" \
  -F "model=MODEL_ID_FROM_V1_MODELS" \
  -F "image=@product.png" \
  -F "mask=@mask.png" \
  -F "prompt=Замени фон на светлую студию" \
  -F "size=1024x1024"

Маска и точные multipart-поля поддерживаются не каждой моделью. Изображение отправляется файлом, поэтому заголовок Content-Type вручную задавать не нужно.

АЛГОРИТМ

Что показать пользователю

  1. 1Покажите состояние генерации и не отправляйте повторный запрос по двойному клику.
  2. 2После ответа скачайте URL или декодируйте base64 на своём сервере.
  3. 3Сохраните файл и свяжите его с пользователем и диалогом в БД.
  4. 4Верните браузеру свой защищённый URL изображения, а не секретный API-ключ.
АНАЛИЗ ИЗОБРАЖЕНИЙ

Передайте картинку в диалог

Если выбранная модель поддерживает зрение, сообщение может содержать текст и image_url. URL должен быть доступен серверу либо содержать Data URL с base64.

CHAT COMPLETIONS · VISION

Публичный URL изображения

curl https://rucodex.ru/v1/chat/completions \
  -H "Authorization: Bearer $RUCODEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "VISION_MODEL_ID_FROM_V1_MODELS",
    "messages": [{
      "role": "user",
      "content": [
        {"type": "text", "text": "Опиши изображение и найди ошибки интерфейса"},
        {"type": "image_url", "image_url": {
          "url": "https://example.com/screenshot.png"
        }}
      ]
    }]
  }'
Локальный файл

Преобразуйте его в Data URL вида data:image/png;base64,... и передайте в поле url. Учитывайте ограничение RUcodex на весь запрос до 50 МБ и реальные ограничения выбранной модели.

ФАЙЛЫ

Загрузка документов для поддерживаемых сценариев

Маршруты /v1/files и связанные OpenAI-совместимые ресурсы проксируются RUcodex. Их назначение и доступность зависят от возможностей основного API и выбранной модели.

ЗАГРУЗКА

Файл через multipart

curl https://rucodex.ru/v1/files \
  -H "Authorization: Bearer $RUCODEX_API_KEY" \
  -F "purpose=assistants" \
  -F "file=@manual.pdf"
ОТВЕТ

Сохраните file id

{
  "id": "file_...",
  "object": "file",
  "filename": "manual.pdf",
  "purpose": "assistants"
}

Сам факт загрузки не добавляет документ в диалог. Передайте полученный ID тем способом, который требует выбранный endpoint и модель.

МЕТОДЫ RUCODEX

Краткий справочник

Основные методы ниже проверены шлюзом RUcodex. Дополнительные OpenAI-совместимые ресурсы доступны при их поддержке основным API.

GET/v1/models

Список моделей

Модели аккаунта. Без подписки возвращается rucodex-test.

POST/v1/chat/completions

Chat Completions

Роли, история messages, tools, изображения и stream: true при поддержке модели.

POST/v1/responses

Responses API

Современный интерфейс для текста, изображений и инструментов.

POST/v1/images/generations

Создание изображений

Возвращает URL или base64 в OpenAI-совместимой структуре.

POST/v1/images/edits

Редактирование

Multipart-загрузка изображения, маски и инструкции.

POST/v1/embeddings

Embeddings

Векторные представления текста, если доступна подходящая модель.

POST/v1/audio/*

Аудио

Синтез речи, транскрибация и перевод при поддержке основного API.

API/v1/files · /batches · /threads

Дополнительные ресурсы

Проксируются для совместимых клиентов; конкретные операции зависят от upstream.

МОДЕЛИ

Всегда актуальный список

Не закрепляйте каталог в коде. Получайте его через GET /v1/models: после покупки подписки набор обновится автоматически.

Войдите, чтобы увидеть модели вашего аккаунта
ОШИБКИ И НАДЁЖНОСТЬ

Что делать, если запрос не выполнен

Сначала проверяйте HTTP-статус, затем читайте error.message. Не повторяйте бездумно запросы, которые могут создать платный или необратимый результат.

400

Некорректный запрос

Проверьте JSON, model, обязательные поля и поддержку параметров.

401

Ключ недействителен

Ключ отсутствует, введён неверно или отозван.

402

Нужна подписка

Для бесплатной проверки используйте rucodex-test.

429

Лимит исчерпан

Дождитесь освобождения окна или увеличьте тариф.

5xx

Временный сбой

Повторите безопасный запрос с увеличивающейся задержкой.

PHP 8.3 · RETRY

Повтор только временных ошибок

function requestWithRetry(callable $request, int $maxAttempts = 4): array
{
    for ($attempt = 1; $attempt <= $maxAttempts; $attempt++) {
        [$status, $body] = $request();

        if ($status < 400) return $body;

        $temporary = $status === 429 || $status >= 500;
        if (!$temporary || $attempt === $maxAttempts) {
            throw new RuntimeException($body['error']['message'] ?? "HTTP $status");
        }

        // 0.5, 1, 2, 4 секунды + случайная добавка против одновременных повторов.
        $delayMs = (500 * (2 ** ($attempt - 1))) + random_int(0, 250);
        usleep($delayMs * 1000);
    }

    throw new RuntimeException('Запрос не выполнен');
}
{
  "error": {
    "message": "Описание ошибки",
    "type": "rate_limit_error",
    "param": null,
    "code": "rate_limit_exceeded"
  }
}
ДИАГНОСТИКА

Сохраняйте идентификатор запроса

Записывайте время, endpoint, модель, HTTP-статус и заголовок X-RUcodex-Request-Id, но никогда не записывайте полный API-ключ и персональные данные без необходимости.

Таймауты

Соединение: 10–15 секунд. Полный ответ: 120 секунд или больше для изображений.

Повторы

Обычно повторяют 429 и 5xx. Для 400/401/402 сначала исправляют причину.

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

Для операций создания используйте собственный ID операции и защищайтесь от двойного клика.

Секреты

Один ключ на приложение. При утечке отзовите его в настройках и выпустите новый.