Authorization: Bearer rucodex_sk_...Ключ передаётся в каждом запросе. Префикс Bearer обязателен.
Полное руководство по RUcodex API: как вести диалог без потери контекста, показывать ответ по мере генерации, вызывать функции вашего приложения, анализировать и создавать изображения.
// 1. Храните историю у себя
messages = [
{ role: "system", content: "Ты помощник" },
{ role: "user", content: "Меня зовут Анна" }
]
// 2. Добавьте ответ AI
messages.push(response.choices[0].message)
// 3. Добавьте следующий вопрос
messages.push({
role: "user",
content: "Как меня зовут?"
})
// 4. Отправьте весь messages сноваhttps://api.openai.com/v1https://rucodex.ru/v1Читайте последовательно или сразу переходите к нужному сценарию. В каждом разделе есть готовые запросы и пояснение структуры ответа.
Создать ключ можно сразу после регистрации. Без тарифа он работает с бесплатной моделью rucodex-test, а после оплаты автоматически получает доступ к моделям подписки.
Authorization: Bearer rucodex_sk_...Ключ передаётся в каждом запросе. Префикс Bearer обязателен.
RUCODEX_API_KEYХраните ключ в переменной окружения на сервере. Не вставляйте его в браузерный JavaScript.
GET /v1/modelsПолучайте доступный каталог программно: набор моделей меняется вместе с тарифом.
Выберите привычный инструмент. Для бесплатной проверки используйте rucodex-test; при активной подписке — идентификатор из GET /v1/models.
Полное значение показывается один раз. Сохраните его как секрет.
Вызовите GET /v1/models и используйте точное значение поля id.
Для 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Идентификатор запроса; сохраняйте его в журнале для диагностики.Каждый API-запрос сам по себе независим. Для Chat Completions ваше приложение хранит историю и отправляет её заново при каждом сообщении.
После ответа добавьте объект assistant в историю, затем добавьте новое сообщение user и отправьте весь массив messages. Одного текста последнего вопроса недостаточно.
Добавьте вопрос с ролью user
Получите объект assistant
Сохраните оба сообщения
Отправьте всю историю снова
<?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": [
{
"role": "system",
"content": "Ты финансовый помощник"
},
{
"role": "user",
"content": "Мой бюджет — 80 000 ₽"
},
{
"role": "assistant",
"content": "Зафиксировал бюджет"
},
{
"role": "user",
"content": "Предложи распределение"
}
]
systemuserassistanttooltool_call_id.Разделяйте чаты. Храните сообщения по паре user_id + chat_id, чтобы контекст разных диалогов не смешивался.
Сохраняйте порядок. Записывайте роль, content, tool_calls и время каждого сообщения.
Контролируйте размер. Когда история становится большой, суммируйте старую часть отдельным запросом и оставляйте резюме плюс последние сообщения.
Не доверяйте браузеру. История и API-ключ должны передаваться через ваш сервер, где можно проверить владельца чата.
Responses API объединяет текст, изображения и инструменты в одном интерфейсе. RUcodex передаёт его параметры и ответ в OpenAI-совместимом формате.
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) # Сохраните для продолжения
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Состояние выполнения; перед показом результата проверяйте успешное завершение.Передайте stream: true. Сервер вернёт поток событий data:; текст приходит частями в choices[0].delta.content, а маркер [DONE] завершает поток.
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
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 в истории диалога
$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-статус.
Модель не вызывает вашу функцию самостоятельно. Она возвращает имя и аргументы; ваш сервер проверяет их, выполняет действие и отправляет результат обратно.
Передайте описание функции в tools
Прочитайте message.tool_calls
Проверьте аргументы и выполните свой код
Отправьте роль tool и получите финальный текст
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)
Считайте аргументы модели недоверенными данными. Разрешайте только известные функции, валидируйте типы и права пользователя, ограничивайте суммы и никогда не выполняйте полученную строку как SQL, PHP или shell-команду.
Генерация выполняется через POST /v1/images/generations. В зависимости от модели результат содержит временный url или строку b64_json.
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, качество и поддержка прозрачности зависят от выбранной модели.
{
"created": 1786150800,
"data": [{
"url": "https://.../temporary-image.png",
"b64_json": null,
"revised_prompt": "Уточнённое описание..."
}]
}
Проверяйте оба поля. Если пришёл URL — скачайте файл сразу: ссылка может быть временной. Если пришёл b64_json — декодируйте его в бинарный файл.
<?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);
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 вручную задавать не нужно.
Если выбранная модель поддерживает зрение, сообщение может содержать текст и image_url. URL должен быть доступен серверу либо содержать Data URL с base64.
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 и выбранной модели.
curl https://rucodex.ru/v1/files \
-H "Authorization: Bearer $RUCODEX_API_KEY" \
-F "purpose=assistants" \
-F "file=@manual.pdf"
{
"id": "file_...",
"object": "file",
"filename": "manual.pdf",
"purpose": "assistants"
}
Сам факт загрузки не добавляет документ в диалог. Передайте полученный ID тем способом, который требует выбранный endpoint и модель.
Основные методы ниже проверены шлюзом RUcodex. Дополнительные OpenAI-совместимые ресурсы доступны при их поддержке основным API.
/v1/modelsМодели аккаунта. Без подписки возвращается rucodex-test.
/v1/chat/completionsРоли, история messages, tools, изображения и stream: true при поддержке модели.
/v1/responsesСовременный интерфейс для текста, изображений и инструментов.
/v1/images/generationsВозвращает URL или base64 в OpenAI-совместимой структуре.
/v1/images/editsMultipart-загрузка изображения, маски и инструкции.
/v1/embeddingsВекторные представления текста, если доступна подходящая модель.
/v1/audio/*Синтез речи, транскрибация и перевод при поддержке основного API.
/v1/files · /batches · /threadsПроксируются для совместимых клиентов; конкретные операции зависят от upstream.
Не закрепляйте каталог в коде. Получайте его через GET /v1/models: после покупки подписки набор обновится автоматически.
Сначала проверяйте HTTP-статус, затем читайте error.message. Не повторяйте бездумно запросы, которые могут создать платный или необратимый результат.
Проверьте JSON, model, обязательные поля и поддержку параметров.
Ключ отсутствует, введён неверно или отозван.
Для бесплатной проверки используйте rucodex-test.
Дождитесь освобождения окна или увеличьте тариф.
Повторите безопасный запрос с увеличивающейся задержкой.
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 операции и защищайтесь от двойного клика.
Один ключ на приложение. При утечке отзовите его в настройках и выпустите новый.