API-справочник
Обязательны Content-Type: application/json и Bearer. Тело — JSON-объект, максимум 16 MiB. model — публичный ID. Заголовок Idempotency-Key рекомендован для повторов.
Для /chat/completions обязательны непустые messages. Для /videos обязательны model и prompt. /images принимает prompt и применимые поля изображений. Неподдержанный параметр не игнорируется.
HTTP 200: готовый chat/image-результат с собственными id, model и ai_service.request_id/billing. HTTP 202: объект ai_service.request с собственным ID; результат получайте опросом. HTTP 502: завершившаяся ошибка с request_id и billing.
Не повторяйте оплачиваемый запрос с новым ключом только из-за HTTP-таймаута. Сначала получите существующий запрос по прежнему ключу или ID.
Prefer: respond-async выбирает очередь без ожидания поставщика; сервер подтверждает его заголовком Preference-Applied. Заголовки X-Generation-ID и Location связывают принятый POST с GET /requests/{id}. Предпочтение не входит в параметры генерации: его можно изменить при повторе с тем же Idempotency-Key. Если готовый результат уже сохранён, повтор возвращает его обычным форматом; истёкшее содержимое — 410.
cURL · POST /chat/completions
curl "https://formula-ai.ru/api/v1/chat/completions" \
-H "Authorization: Bearer $AI_SERVICE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: example-text-1" \
--data-binary "{
\"model\": \"$AI_SERVICE_MODEL\",
\"messages\": [
{
\"role\": \"user\",
\"content\": \"Reply OK\"
}
]
}"
cURL · POST /images
curl "https://formula-ai.ru/api/v1/images" \
-H "Authorization: Bearer $AI_SERVICE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: example-images-1" \
--data-binary "{
\"model\": \"$AI_SERVICE_MODEL\",
\"prompt\": \"A red circle on a white background\",
\"response_format\": \"url\"
}"
cURL · POST /videos
curl "https://formula-ai.ru/api/v1/videos" \
-H "Authorization: Bearer $AI_SERVICE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: example-videos-1" \
--data-binary "{
\"model\": \"$AI_SERVICE_MODEL\",
\"prompt\": \"A paper boat floating on a quiet pond\"
}"
PHP · POST /chat/completions
<?php
$key = getenv("AI_SERVICE_API_KEY");
$url = "https://formula-ai.ru/api/v1/chat/completions";
$handle = curl_init($url);
curl_setopt_array($handle, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode(["model" => getenv("AI_SERVICE_MODEL"), "messages" => [["role" => "user", "content" => "Reply OK"]]], JSON_THROW_ON_ERROR),
CURLOPT_HTTPHEADER => ["Authorization: Bearer " . $key, "Content-Type: application/json", "Idempotency-Key: first-text-1"],
]);
if (getenv("AI_SERVICE_CA")) {
curl_setopt($handle, CURLOPT_CAINFO, getenv("AI_SERVICE_CA"));
}
$body = curl_exec($handle);
if ($body === false) {
throw new RuntimeException(curl_error($handle));
}
$status = curl_getinfo($handle, CURLINFO_RESPONSE_CODE);
curl_close($handle);
$result = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
echo json_encode(["status" => $status, "result" => $result], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);
PHP · POST /images
<?php
$key = getenv("AI_SERVICE_API_KEY");
$url = "https://formula-ai.ru/api/v1/images";
$handle = curl_init($url);
curl_setopt_array($handle, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode(["model" => getenv("AI_SERVICE_MODEL"), "prompt" => "A red circle on a white background"], JSON_THROW_ON_ERROR),
CURLOPT_HTTPHEADER => ["Authorization: Bearer " . $key, "Content-Type: application/json", "Idempotency-Key: php-images-1"],
]);
if (getenv("AI_SERVICE_CA")) {
curl_setopt($handle, CURLOPT_CAINFO, getenv("AI_SERVICE_CA"));
}
$body = curl_exec($handle);
if ($body === false) {
throw new RuntimeException(curl_error($handle));
}
$status = curl_getinfo($handle, CURLINFO_RESPONSE_CODE);
curl_close($handle);
$result = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
echo json_encode(["status" => $status, "result" => $result], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);
PHP · POST /videos
<?php
$key = getenv("AI_SERVICE_API_KEY");
$url = "https://formula-ai.ru/api/v1/videos";
$handle = curl_init($url);
curl_setopt_array($handle, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode(["model" => getenv("AI_SERVICE_MODEL"), "prompt" => "A red circle on a white background"], JSON_THROW_ON_ERROR),
CURLOPT_HTTPHEADER => ["Authorization: Bearer " . $key, "Content-Type: application/json", "Idempotency-Key: php-videos-1"],
]);
if (getenv("AI_SERVICE_CA")) {
curl_setopt($handle, CURLOPT_CAINFO, getenv("AI_SERVICE_CA"));
}
$body = curl_exec($handle);
if ($body === false) {
throw new RuntimeException(curl_error($handle));
}
$status = curl_getinfo($handle, CURLINFO_RESPONSE_CODE);
curl_close($handle);
$result = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
echo json_encode(["status" => $status, "result" => $result], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);
Схемы метода
Обязательные поля, типы, параметры и ответы описаны в OpenAPI 3.1. Полный машинный справочник
Показать JSON-схемы
{
"openapi": "3.1.1",
"info": {
"title": "Formula AI API",
"version": "1",
"description": "Методы нашего сервиса. Доступность модели и её параметров определяется опубликованным проверенным маршрутом. Suno: 23 музыкальные и вспомогательные операции, схемы и ограничения параметров. Streaming текста, изображений и аудио: SSE, сохранённые части и собственный расчёт."
},
"servers": [
{
"url": "https://formula-ai.ru/api/v1"
}
],
"security": [
{
"ClientKey": []
}
],
"paths": {
"/chat/completions": {
"post": {
"operationId": "createChat",
"summary": "Диалог, изображения и аудио",
"description": "JSON-объект. Действуют ограничения выбранной модели и серверного окружения. Параметры допускаются только совместимым проверенным маршрутом; неподдержанные поля не отбрасываются. Повтор с прежним Idempotency-Key возвращает существующую операцию. После очистки её содержимого возвращается 410.",
"parameters": [
{
"name": "Idempotency-Key",
"in": "header",
"required": false,
"schema": {
"type": "string",
"minLength": 1,
"maxLength": 191,
"pattern": "^[A-Za-z0-9._:\\-]+$"
},
"description": "Область ключа — клиент. Изменение параметров с прежним ключом даёт 409."
},
{
"name": "Prefer",
"in": "header",
"schema": {
"type": "string"
},
"description": "respond-async: вернуть собственный ID без ожидания поставщика, в том числе при stream=true. Формат тела и Idempotency-Key сохраняются. Готовый повтор возвращает сохранённый результат."
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ChatInput"
}
}
}
},
"responses": {
"200": {
"description": "Готовый результат и клиентский расчёт.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ChatResult"
}
},
"text/event-stream": {
"schema": {
"type": "string",
"description": "При stream=true: data: JSON и пустая строка; завершение data: [DONE]. Последний JSON содержит ai_service.status/billing. После начала выдачи ошибка передаётся в data.error; проверяйте итоговый статус."
},
"x-item-schema": {
"$ref": "#/components/schemas/StreamChunk"
},
"x-error-schema": {
"$ref": "#/components/schemas/StreamError"
}
}
},
"headers": {
"X-Generation-ID": {
"schema": {
"$ref": "#/components/schemas/PublicId"
}
}
}
},
"202": {
"description": "Операция принята. Опросите GET /requests/{id}.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Request"
}
}
},
"headers": {
"X-Generation-ID": {
"schema": {
"$ref": "#/components/schemas/PublicId"
}
},
"Location": {
"schema": {
"type": "string"
},
"description": "Путь GET /api/v1/requests/{id}."
},
"Preference-Applied": {
"schema": {
"type": "string",
"const": "respond-async"
}
}
}
},
"502": {
"description": "Генерация завершилась ошибкой. Проверьте billing.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GenerationError"
}
}
},
"headers": {
"X-Generation-ID": {
"schema": {
"$ref": "#/components/schemas/PublicId"
}
}
}
},
"default": {
"description": "Ошибка валидации, настроек, доступа или баланса.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"headers": {
"X-Generation-ID": {
"schema": {
"$ref": "#/components/schemas/PublicId"
}
}
}
}
}
}
},
"/images": {
"post": {
"operationId": "createImages",
"summary": "Генерация и редактирование изображений",
"description": "JSON-объект. Действуют ограничения выбранной модели и серверного окружения. Параметры допускаются только совместимым проверенным маршрутом; неподдержанные поля не отбрасываются. Повтор с прежним Idempotency-Key возвращает существующую операцию. После очистки её содержимого возвращается 410.",
"parameters": [
{
"name": "Idempotency-Key",
"in": "header",
"required": false,
"schema": {
"type": "string",
"minLength": 1,
"maxLength": 191,
"pattern": "^[A-Za-z0-9._:\\-]+$"
},
"description": "Область ключа — клиент. Изменение параметров с прежним ключом даёт 409."
},
{
"name": "Prefer",
"in": "header",
"schema": {
"type": "string"
},
"description": "respond-async: вернуть собственный ID без ожидания поставщика, в том числе при stream=true. Формат тела и Idempotency-Key сохраняются. Готовый повтор возвращает сохранённый результат."
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ImageInput"
}
}
}
},
"responses": {
"200": {
"description": "Готовый результат и клиентский расчёт.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ImageResult"
}
},
"text/event-stream": {
"schema": {
"type": "string",
"description": "При stream=true события data.type: partial_image, completed, settled с префиксом image_generation.; затем [DONE]. Превью зависит от модели."
},
"x-item-schema": {
"$ref": "#/components/schemas/ImageStreamEvent"
},
"x-error-schema": {
"$ref": "#/components/schemas/StreamError"
}
}
},
"headers": {
"X-Generation-ID": {
"schema": {
"$ref": "#/components/schemas/PublicId"
}
}
}
},
"202": {
"description": "Операция принята. Опросите GET /requests/{id}.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Request"
}
}
},
"headers": {
"X-Generation-ID": {
"schema": {
"$ref": "#/components/schemas/PublicId"
}
},
"Location": {
"schema": {
"type": "string"
},
"description": "Путь GET /api/v1/requests/{id}."
},
"Preference-Applied": {
"schema": {
"type": "string",
"const": "respond-async"
}
}
}
},
"502": {
"description": "Генерация завершилась ошибкой. Проверьте billing.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GenerationError"
}
}
},
"headers": {
"X-Generation-ID": {
"schema": {
"$ref": "#/components/schemas/PublicId"
}
}
}
},
"default": {
"description": "Ошибка валидации, настроек, доступа или баланса.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"headers": {
"X-Generation-ID": {
"schema": {
"$ref": "#/components/schemas/PublicId"
}
}
}
}
}
}
},
"/images/generations": {
"post": {
"operationId": "generateImages",
"summary": "Псевдоним /images",
"description": "JSON-объект. Действуют ограничения выбранной модели и серверного окружения. Параметры допускаются только совместимым проверенным маршрутом; неподдержанные поля не отбрасываются. Повтор с прежним Idempotency-Key возвращает существующую операцию. После очистки её содержимого возвращается 410.",
"parameters": [
{
"name": "Idempotency-Key",
"in": "header",
"required": false,
"schema": {
"type": "string",
"minLength": 1,
"maxLength": 191,
"pattern": "^[A-Za-z0-9._:\\-]+$"
},
"description": "Область ключа — клиент. Изменение параметров с прежним ключом даёт 409."
},
{
"name": "Prefer",
"in": "header",
"schema": {
"type": "string"
},
"description": "respond-async: вернуть собственный ID без ожидания поставщика, в том числе при stream=true. Формат тела и Idempotency-Key сохраняются. Готовый повтор возвращает сохранённый результат."
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ImageInput"
}
}
}
},
"responses": {
"200": {
"description": "Готовый результат и клиентский расчёт.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ImageResult"
}
},
"text/event-stream": {
"schema": {
"type": "string",
"description": "При stream=true события data.type: partial_image, completed, settled с префиксом image_generation.; затем [DONE]. Превью зависит от модели."
},
"x-item-schema": {
"$ref": "#/components/schemas/ImageStreamEvent"
},
"x-error-schema": {
"$ref": "#/components/schemas/StreamError"
}
}
},
"headers": {
"X-Generation-ID": {
"schema": {
"$ref": "#/components/schemas/PublicId"
}
}
}
},
"202": {
"description": "Операция принята. Опросите GET /requests/{id}.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Request"
}
}
},
"headers": {
"X-Generation-ID": {
"schema": {
"$ref": "#/components/schemas/PublicId"
}
},
"Location": {
"schema": {
"type": "string"
},
"description": "Путь GET /api/v1/requests/{id}."
},
"Preference-Applied": {
"schema": {
"type": "string",
"const": "respond-async"
}
}
}
},
"502": {
"description": "Генерация завершилась ошибкой. Проверьте billing.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GenerationError"
}
}
},
"headers": {
"X-Generation-ID": {
"schema": {
"$ref": "#/components/schemas/PublicId"
}
}
}
},
"default": {
"description": "Ошибка валидации, настроек, доступа или баланса.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"headers": {
"X-Generation-ID": {
"schema": {
"$ref": "#/components/schemas/PublicId"
}
}
}
}
}
}
},
"/videos": {
"post": {
"operationId": "createVideo",
"summary": "Генерация видео",
"description": "JSON-объект. Действуют ограничения выбранной модели и серверного окружения. Параметры допускаются только совместимым проверенным маршрутом; неподдержанные поля не отбрасываются. Повтор с прежним Idempotency-Key возвращает существующую операцию. После очистки её содержимого возвращается 410.",
"parameters": [
{
"name": "Idempotency-Key",
"in": "header",
"required": false,
"schema": {
"type": "string",
"minLength": 1,
"maxLength": 191,
"pattern": "^[A-Za-z0-9._:\\-]+$"
},
"description": "Область ключа — клиент. Изменение параметров с прежним ключом даёт 409."
},
{
"name": "Prefer",
"in": "header",
"schema": {
"type": "string"
},
"description": "respond-async: вернуть собственный ID без ожидания поставщика, в том числе при stream=true. Формат тела и Idempotency-Key сохраняются. Готовый повтор возвращает сохранённый результат."
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/VideoInput"
}
}
}
},
"responses": {
"202": {
"description": "Операция принята. Опросите GET /requests/{id}.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Request"
}
}
},
"headers": {
"X-Generation-ID": {
"schema": {
"$ref": "#/components/schemas/PublicId"
}
},
"Location": {
"schema": {
"type": "string"
},
"description": "Путь GET /api/v1/requests/{id}."
},
"Preference-Applied": {
"schema": {
"type": "string",
"const": "respond-async"
}
}
}
},
"502": {
"description": "Генерация завершилась ошибкой. Проверьте billing.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GenerationError"
}
}
},
"headers": {
"X-Generation-ID": {
"schema": {
"$ref": "#/components/schemas/PublicId"
}
}
}
},
"default": {
"description": "Ошибка валидации, настроек, доступа или баланса.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"headers": {
"X-Generation-ID": {
"schema": {
"$ref": "#/components/schemas/PublicId"
}
}
}
}
}
}
},
"/music/generations": {
"post": {
"operationId": "createMusic",
"summary": "Генерация музыки",
"description": "JSON-объект. Действуют ограничения выбранной модели и серверного окружения. Параметры допускаются только совместимым проверенным маршрутом; неподдержанные поля не отбрасываются. Повтор с прежним Idempotency-Key возвращает существующую операцию. После очистки её содержимого возвращается 410.",
"parameters": [
{
"name": "Idempotency-Key",
"in": "header",
"required": false,
"schema": {
"type": "string",
"minLength": 1,
"maxLength": 191,
"pattern": "^[A-Za-z0-9._:\\-]+$"
},
"description": "Область ключа — клиент. Изменение параметров с прежним ключом даёт 409."
},
{
"name": "Prefer",
"in": "header",
"schema": {
"type": "string"
},
"description": "respond-async: вернуть собственный ID без ожидания поставщика, в том числе при stream=true. Формат тела и Idempotency-Key сохраняются. Готовый повтор возвращает сохранённый результат."
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MusicInput"
}
}
}
},
"responses": {
"202": {
"description": "Операция принята. Опросите GET /requests/{id}.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Request"
}
}
},
"headers": {
"X-Generation-ID": {
"schema": {
"$ref": "#/components/schemas/PublicId"
}
},
"Location": {
"schema": {
"type": "string"
},
"description": "Путь GET /api/v1/requests/{id}."
},
"Preference-Applied": {
"schema": {
"type": "string",
"const": "respond-async"
}
}
}
},
"502": {
"description": "Генерация завершилась ошибкой. Проверьте billing.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GenerationError"
}
}
},
"headers": {
"X-Generation-ID": {
"schema": {
"$ref": "#/components/schemas/PublicId"
}
}
}
},
"default": {
"description": "Ошибка валидации, настроек, доступа или баланса.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"headers": {
"X-Generation-ID": {
"schema": {
"$ref": "#/components/schemas/PublicId"
}
}
}
}
}
}
}
},
"components": {
"securitySchemes": {
"ClientKey": {
"type": "http",
"scheme": "bearer",
"description": "API-ключ клиента Formula AI."
}
},
"schemas": {
"PublicId": {
"type": "string",
"pattern": "^[a-f0-9]{32}$"
},
"Billing": {
"type": "object",
"properties": {
"currency": {
"const": "RUB"
},
"charged": {
"type": "string",
"pattern": "^-?[0-9]+\\.[0-9]{7}$",
"description": "Рубли, точная десятичная строка с 7 знаками."
},
"refunded": {
"type": "string",
"pattern": "^-?[0-9]+\\.[0-9]{7}$",
"description": "Рубли, точная десятичная строка с 7 знаками."
},
"status": {
"enum": [
"pending",
"confirmed"
]
}
},
"required": [
"currency",
"charged",
"refunded",
"status"
]
},
"Usage": {
"type": "object",
"description": "Применимые единицы: prompt_tokens, completion_tokens, total_tokens, input_tokens, output_tokens, token_details, images, videos, audio_seconds, duration_seconds. Счётчики могут быть точными численными строками. Поля себестоимости не выдаются."
},
"ErrorDetail": {
"type": "object",
"properties": {
"message": {
"type": "string"
},
"code": {
"type": "string"
},
"type": {
"type": "string"
},
"param": {
"type": [
"string",
"null"
]
}
},
"required": [
"message",
"code"
]
},
"Error": {
"type": "object",
"properties": {
"error": {
"$ref": "#/components/schemas/ErrorDetail"
},
"request_id": {
"$ref": "#/components/schemas/PublicId"
}
},
"required": [
"error",
"request_id"
]
},
"GenerationError": {
"type": "object",
"properties": {
"error": {
"$ref": "#/components/schemas/ErrorDetail"
},
"request_id": {
"$ref": "#/components/schemas/PublicId"
},
"billing": {
"$ref": "#/components/schemas/Billing"
}
},
"required": [
"error",
"request_id",
"billing"
]
},
"Request": {
"type": "object",
"properties": {
"id": {
"$ref": "#/components/schemas/PublicId"
},
"object": {
"const": "ai_service.request"
},
"model": {
"type": "string"
},
"operation": {
"type": "string"
},
"status": {
"enum": [
"queued",
"running",
"waiting",
"saving_media",
"uncertain",
"completed",
"failed",
"cancelled"
]
},
"created_at": {
"type": [
"string",
"null"
],
"description": "Время сервиса Europe/Moscow: YYYY-MM-DD HH:mm:ss, возможно дробная часть секунд."
},
"finished_at": {
"type": [
"string",
"null"
],
"description": "Время сервиса Europe/Moscow: YYYY-MM-DD HH:mm:ss, возможно дробная часть секунд."
},
"content_expires_at": {
"type": [
"string",
"null"
],
"description": "Время сервиса Europe/Moscow: YYYY-MM-DD HH:mm:ss, возможно дробная часть секунд."
},
"content_expired": {
"type": "boolean"
},
"usage": {
"$ref": "#/components/schemas/Usage"
},
"billing": {
"$ref": "#/components/schemas/Billing"
},
"result": {
"type": [
"object",
"null"
],
"description": "Результат выбранной операции. Файлы — только адреса Formula AI либо запрошенный base64."
},
"error": {
"anyOf": [
{
"$ref": "#/components/schemas/ErrorDetail"
},
{
"type": "null"
}
]
}
},
"required": [
"id",
"object",
"model",
"operation",
"status",
"created_at",
"finished_at",
"content_expires_at",
"content_expired",
"usage",
"billing",
"result",
"error"
]
},
"ChatInput": {
"type": "object",
"properties": {
"model": {
"type": "string",
"minLength": 1
},
"messages": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/components/schemas/Message"
}
},
"stream": {
"type": "boolean",
"default": false,
"description": "Потоковая выдача текста или аудио. Маршрут обязан поддерживать этот протокол; аудио требует stream=true."
},
"temperature": {
"type": "number",
"minimum": 0,
"maximum": 2
},
"top_p": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"frequency_penalty": {
"type": "number",
"minimum": -2,
"maximum": 2
},
"presence_penalty": {
"type": "number",
"minimum": -2,
"maximum": 2
},
"max_tokens": {
"type": "integer",
"minimum": 1
},
"max_completion_tokens": {
"type": "integer",
"minimum": 1
},
"n": {
"type": "integer",
"minimum": 1
},
"seed": {
"type": "integer"
},
"stop": {
"type": [
"string",
"array"
]
},
"tools": {
"type": "array",
"items": {
"type": "object"
},
"description": "Функции в формате Chat Completions; type=function и function.name/parameters. Поддержка зависит от модели."
},
"tool_choice": {
"type": [
"string",
"object"
]
},
"response_format": {
"type": "object",
"properties": {
"type": {
"enum": [
"text",
"json_object",
"json_schema"
]
},
"json_schema": {
"type": "object"
}
},
"required": [
"type"
]
},
"reasoning": {
"type": "object"
},
"reasoning_effort": {
"type": "string"
},
"modalities": {
"type": "array",
"items": {
"type": "string"
}
},
"image_config": {
"type": "object",
"properties": {
"aspect_ratio": {
"type": "string"
},
"image_size": {
"enum": [
"512",
"1K",
"2K",
"4K"
]
}
},
"required": []
},
"audio": {
"type": "object",
"properties": {
"voice": {
"enum": [
"alloy",
"ash",
"ballad",
"coral",
"echo",
"fable",
"onyx",
"nova",
"sage",
"shimmer",
"verse"
]
},
"format": {
"const": "pcm16"
}
},
"required": [
"voice",
"format"
],
"additionalProperties": false
},
"stream_options": {
"type": "object",
"properties": {
"include_usage": {
"type": "boolean"
}
},
"required": [
"include_usage"
],
"additionalProperties": false
}
},
"required": [
"model",
"messages"
],
"allOf": [
{
"if": {
"required": [
"stream_options"
]
},
"then": {
"properties": {
"stream": {
"const": true
}
},
"required": [
"stream"
]
}
},
{
"if": {
"required": [
"modalities"
],
"properties": {
"modalities": {
"contains": {
"const": "audio"
}
}
}
},
"then": {
"required": [
"stream",
"audio"
],
"properties": {
"stream": {
"const": true
},
"modalities": {
"type": "array",
"minItems": 2,
"maxItems": 2,
"uniqueItems": true,
"items": {
"enum": [
"text",
"audio"
]
}
}
}
}
}
],
"description": "Полный набор полей ограничивается возможностями выбранной модели. Аудио: modalities=[text,audio], audio.voice и audio.format=pcm16, моно 24 кГц. Параметры инструментов, формата ответа и image_config не универсальны."
},
"AudioChunk": {
"type": "object",
"properties": {
"data": {
"type": "string",
"minLength": 1,
"contentEncoding": "base64",
"description": "Независимый base64 фрагмента PCM16, моно 24 кГц. Декодировать каждый фрагмент отдельно и соединять байты."
},
"transcript": {
"type": "string"
}
},
"required": [],
"additionalProperties": false
},
"AudioResult": {
"type": "object",
"properties": {
"url": {
"type": "string",
"format": "uri",
"description": "Защищённый файл Formula AI; для скачивания нужен исходный клиентский Bearer-ключ."
},
"format": {
"const": "pcm16"
},
"sample_rate": {
"const": 24000
},
"channels": {
"const": 1
},
"transcript": {
"type": "string"
}
},
"required": [
"url",
"format",
"sample_rate",
"channels"
],
"additionalProperties": false
},
"StreamDelta": {
"type": "object",
"properties": {
"role": {
"type": [
"string",
"null"
]
},
"content": {
"type": [
"string",
"null"
]
},
"reasoning": {
"type": [
"string",
"null"
]
},
"refusal": {
"type": [
"string",
"null"
]
},
"reasoning_details": {
"type": [
"array",
"null"
]
},
"tool_calls": {
"type": [
"array",
"null"
]
},
"function_call": {
"type": [
"object",
"null"
]
},
"audio": {
"anyOf": [
{
"$ref": "#/components/schemas/AudioChunk"
},
{
"type": "null"
}
]
}
},
"required": [],
"additionalProperties": false
},
"StreamChunk": {
"type": "object",
"properties": {
"id": {
"$ref": "#/components/schemas/PublicId"
},
"object": {
"const": "chat.completion.chunk"
},
"model": {
"type": "string"
},
"created": {
"type": "integer"
},
"choices": {
"type": "array",
"items": {
"type": "object",
"properties": {
"index": {
"type": "integer",
"minimum": 0
},
"delta": {
"$ref": "#/components/schemas/StreamDelta"
},
"finish_reason": {
"type": [
"string",
"null"
]
},
"logprobs": {
"type": [
"object",
"null"
]
}
},
"required": [
"index",
"delta"
]
}
},
"usage": {
"$ref": "#/components/schemas/Usage"
},
"ai_service": {
"type": "object",
"properties": {
"request_id": {
"$ref": "#/components/schemas/PublicId"
},
"status": {
"type": "string"
},
"billing": {
"$ref": "#/components/schemas/Billing"
},
"status_url": {
"type": "string",
"description": "Путь GET /api/v1/requests/{id}, передаётся в начальном событии."
}
},
"required": [
"request_id",
"status",
"billing"
]
}
},
"required": [
"id",
"object",
"model",
"choices"
]
},
"StreamError": {
"type": "object",
"properties": {
"error": {
"$ref": "#/components/schemas/ErrorDetail"
},
"request_id": {
"$ref": "#/components/schemas/PublicId"
}
},
"required": [
"error",
"request_id"
]
},
"ImageStreamEvent": {
"type": "object",
"properties": {
"id": {
"$ref": "#/components/schemas/PublicId"
},
"object": {
"const": "image.generation.event"
},
"model": {
"type": "string"
},
"type": {
"enum": [
"image_generation.partial_image",
"image_generation.completed",
"image_generation.settled",
"image_generation.accepted"
]
},
"created": {
"type": "integer"
},
"image_index": {
"type": "integer",
"minimum": 0
},
"partial_image_index": {
"type": "integer",
"minimum": 0
},
"data": {
"type": "array",
"items": {
"type": "object",
"properties": {
"url": {
"$ref": "#/components/schemas/MediaSource"
},
"b64_json": {
"type": "string"
},
"revised_prompt": {
"type": "string"
}
},
"required": [],
"anyOf": [
{
"required": [
"url"
]
},
{
"required": [
"b64_json"
]
}
]
}
},
"usage": {
"$ref": "#/components/schemas/Usage"
},
"ai_service": {
"type": "object",
"properties": {
"request_id": {
"$ref": "#/components/schemas/PublicId"
},
"status": {
"type": "string"
},
"billing": {
"$ref": "#/components/schemas/Billing"
},
"status_url": {
"type": "string",
"description": "Путь GET /api/v1/requests/{id}, передаётся в начальном событии."
}
},
"required": [
"request_id",
"status",
"billing"
]
}
},
"required": [
"id",
"object",
"model",
"type"
]
},
"ImageInput": {
"type": "object",
"properties": {
"model": {
"type": "string",
"minLength": 1
},
"prompt": {
"type": "string",
"minLength": 1,
"maxLength": 100000
},
"input_references": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/components/schemas/Reference"
}
},
"mask": {
"anyOf": [
{
"$ref": "#/components/schemas/MediaSource"
},
{
"type": "object"
}
]
},
"n": {
"type": "integer",
"minimum": 1
},
"stream": {
"type": "boolean",
"default": false
},
"stream_options": {
"type": "object",
"properties": {
"include_usage": {
"type": "boolean"
}
},
"required": [
"include_usage"
],
"additionalProperties": false
},
"size": {
"type": "string"
},
"aspect_ratio": {
"type": "string"
},
"resolution": {
"type": "string"
},
"quality": {
"type": "string"
},
"background": {
"type": "string"
},
"output_format": {
"type": "string"
},
"output_compression": {
"type": "integer",
"minimum": 0,
"maximum": 100
},
"seed": {
"type": "integer"
},
"response_format": {
"enum": [
"url",
"b64_json"
]
}
},
"required": [
"model"
],
"anyOf": [
{
"required": [
"prompt"
]
},
{
"required": [
"input_references"
]
}
],
"allOf": [
{
"if": {
"required": [
"stream_options"
]
},
"then": {
"properties": {
"stream": {
"const": true
}
},
"required": [
"stream"
]
}
}
],
"description": "Редактирование: input_references. Вариации без prompt допускаются только подтверждённым маршрутом. Маска требует исходного изображения и поддержки моделью. Streaming доступен у совместимого маршрута; превью зависит от модели."
},
"VideoInput": {
"type": "object",
"properties": {
"model": {
"type": "string",
"minLength": 1
},
"prompt": {
"type": "string",
"minLength": 1,
"maxLength": 100000
},
"duration": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"const": -1
}
],
"description": "Seedance 2.5: -1 только с видео-референсом и aspect_ratio=adaptive; длительность исходного видео 4–30 секунд. Для остальных режимов — положительное целое."
},
"resolution": {
"type": "string"
},
"aspect_ratio": {
"type": "string"
},
"size": {
"type": "string"
},
"generate_audio": {
"type": "boolean"
},
"seed": {
"type": "integer"
},
"input_references": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/components/schemas/Reference"
}
},
"frame_images": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"properties": {
"type": {
"const": "image_url"
},
"image_url": {
"type": "object",
"properties": {
"url": {
"$ref": "#/components/schemas/MediaSource"
}
},
"required": [
"url"
]
},
"frame_type": {
"enum": [
"first_frame",
"last_frame"
]
}
},
"required": [
"type",
"image_url",
"frame_type"
]
}
},
"reference_image_urls": {
"type": "array",
"items": {
"$ref": "#/components/schemas/MediaSource"
},
"deprecated": true,
"description": "Seedance 2.5: совместимый прежний формат. Используйте input_references."
},
"reference_video_urls": {
"type": "array",
"items": {
"$ref": "#/components/schemas/MediaSource"
},
"deprecated": true,
"description": "Seedance 2.5: совместимый прежний формат. Используйте input_references."
},
"reference_audio_urls": {
"type": "array",
"items": {
"$ref": "#/components/schemas/MediaSource"
},
"deprecated": true,
"description": "Seedance 2.5: совместимый прежний формат. Используйте input_references."
},
"first_frame_url": {
"$ref": "#/components/schemas/MediaSource",
"deprecated": true,
"description": "Seedance 2.5: совместимый прежний формат. Используйте frame_images."
},
"last_frame_url": {
"$ref": "#/components/schemas/MediaSource",
"deprecated": true,
"description": "Seedance 2.5: совместимый прежний формат. Используйте frame_images."
}
},
"required": [
"model",
"prompt"
],
"description": "Seedance 2.5 использует общий формат RouterAI и Kie.ai. Не смешивайте два представления референсов или кадров. Опорные кадры не совмещаются с референсами; последний кадр Kie.ai требует первого."
},
"MusicInput": {
"type": "object",
"properties": {
"prompt": {
"type": "string",
"description": "A description of the desired audio content. Optional.\n- Custom mode (`custom_mode=true`): When provided, the prompt is used strictly as lyrics and sung in the generated track. Character limits by model:\n - V4: Maximum 3000 characters\n - V4_5, V4_5PLUS, V4_5ALL, V5_5, V5: Maximum 5000 characters\n- Non-custom mode (`custom_mode=false`): When provided, the prompt serves as the core idea. Lyrics are generated automatically based on it and do not strictly match the input. Maximum 3000 characters.\n`prompt` is not required. In non-custom mode, provide at least one of `image_urls`, `video_urls`, `audio_urls`, `style`, or `lyrics`. In custom mode, provide at least one of `style`, `lyrics`, or `negative_tags`. Generation is rejected if all related inputs are empty."
},
"style": {
"type": "string",
"description": "Music style specification for the generated audio.\n- Character limits by model:\n - **V4** (Discontinued): Maximum 200 characters\n - **V4_5 and V4_5PLUS** (Discontinued): Maximum 1000 characters\n - **V4_5ALL** (Discontinued): Maximum 1000 characters\n - **V5_5 and V5** (Discontinued): Maximum 1000 characters\n - **V6, V6_MINI, and V6_WILD**: Maximum 1000 characters\n- Common examples: Jazz, Classical, Electronic, Pop, Rock, Hip-hop, etc.",
"maxLength": 1000
},
"title": {
"type": "string",
"description": "Title for the generated music track.\n- Required in Custom Mode (`custom_mode: true`).\n- Max length: 80 characters.\n- Will be displayed in player interfaces and filenames.",
"maxLength": 80
},
"custom_mode": {
"type": "boolean",
"description": "Determines whether advanced parameter customization is enabled.\n- If `true`: Allows detailed control\n- If `false`: Simplified mode"
},
"instrumental": {
"type": "boolean",
"description": "Determines whether the audio should be instrumental (no lyrics).\n- In Custom Mode (`custom_mode: true`):\n - If `true`: Only `style` and `title` are required.\n - If `false`: `style`, `title`, and `prompt` are required (`prompt` is used as the exact lyrics).\n- In Non-custom Mode (`custom_mode: false`):\n - If `true`: Only `style` and `prompt` are required.\n - If `false`: `style`, `prompt`, and `lyrics` are required (`lyrics` is used as a lyrics attachment and can be used together with the audio description in `prompt`)."
},
"negative_tags": {
"type": "string",
"description": "Music styles or traits to exclude from the generated audio. Optional. Use to avoid specific styles."
},
"vocal_gender": {
"type": "string",
"description": "Vocal gender preference. Optional. Use `m` for male and `f` for female. This parameter is only effective when `custom_mode` is true. In practice, it only increases probability and cannot guarantee male/female voice instructions are followed.",
"enum": [
"m",
"f"
]
},
"style_weight": {
"type": "number",
"description": "Only available when Custom Mode (`custom_mode: true`) is enabled. Strength of adherence to the specified style. Optional. Range 0–1, up to 2 decimal places.",
"minimum": 0,
"maximum": 1,
"multipleOf": 0.01
},
"weirdness_constraint": {
"type": "number",
"description": "Only available when Custom Mode (`custom_mode: true`) is enabled. Controls experimental/creative deviation. Optional. Range 0–1, up to 2 decimal places.",
"minimum": 0,
"maximum": 1,
"multipleOf": 0.01
},
"audio_weight": {
"type": "number",
"description": "Only available when Custom Mode (`custom_mode: true`) is enabled. Relative weight of audio features. Optional. Range 0–1, up to 2 decimal places.\n- `audio_weight` is not supported when there are no vocals",
"minimum": 0,
"maximum": 1,
"multipleOf": 0.01
},
"persona_id": {
"type": "string",
"pattern": "^[a-f0-9]{32}$",
"description": "ID собственного исходного запроса."
},
"persona_model": {
"type": "string",
"enum": [
"style_persona",
"voice_persona"
],
"description": "Persona model. Only available for V5 (Discontinued), V5.5 (Discontinued), V6, V6_MINI, and V6_WILD."
},
"duration": {
"type": "number",
"default": 20,
"minimum": 10,
"maximum": 360,
"description": "Audio duration. Optional; only valid when `custom_mode` is true and the model is V5_5 (Discontinued), V6, V6_MINI, or V6_WILD."
},
"image_urls": {
"type": "array",
"description": "Image references. Only effective when `custom_mode=false`.\n- Optional\n- Up to 5 images; each image must not exceed 10 MB\n- Supported formats: `jpeg`, `png`, `webp`, and `bmp`",
"items": {
"type": "string"
},
"maxItems": 5
},
"variety": {
"type": "integer",
"default": 1,
"minimum": 0,
"maximum": 4,
"multipleOf": 1,
"description": "Only available when Custom Mode (`custom_mode: true`) is enabled. Controls the diversity and stylistic variation of generated results. Optional. Range 0–4, integer, default 1.\n\n- **`0`**: off (exact style) — fully off, strictly the same style\n- **`1`**: normal (balanced variety) — default, balances stability and diversity\n- **`2`**: high (distinct styles) — produces results with clearly different styles\n- **`3`**: extra (bold exploration) — higher variation, encourages bold exploration of different styles\n- **`4`**: max (unreasonably varied) — maximum diversity; results may differ in style very significantly"
},
"lyrics": {
"type": "string",
"description": "Lyrics for the generated audio. Optional.\n- V6: Maximum 5000 characters.\n- When `custom_mode=true`, `lyrics` is used as lyrics first; if `lyrics` is not provided, `prompt` is used as lyrics.\n- When `custom_mode=false`, `lyrics` is used as a lyrics attachment and can be used together with the audio description in `prompt`.",
"maxLength": 5000
},
"audio_urls": {
"type": "array",
"items": {
"type": "string"
},
"description": "Audio references. Only effective when `custom_mode=false`.\n- Optional\n- Audio duration must be between 6 seconds and 30 minutes; each audio file must not exceed 500 MB",
"maxItems": 10
},
"video_urls": {
"type": "array",
"items": {
"type": "string"
},
"description": "Video references. Only effective when `custom_mode=false`.\n- Optional\n- Up to 1 video file; each file must not exceed 100 MB, duration must not exceed 241 seconds, with no minimum duration\n- Supported formats: mp4, mov, and webm",
"maxItems": 1
},
"model": {
"type": "string",
"minLength": 1,
"description": "Публичный ID Suno из GET /models."
}
},
"required": [
"model",
"custom_mode",
"instrumental"
],
"additionalProperties": false,
"allOf": [
{
"if": {
"properties": {
"custom_mode": {
"const": true
}
},
"required": [
"custom_mode"
]
},
"then": {
"required": [
"title"
],
"properties": {
"prompt": {
"maxLength": 5000
},
"title": {
"minLength": 1
},
"image_urls": {
"maxItems": 0
},
"video_urls": {
"maxItems": 0
},
"audio_urls": {
"maxItems": 0
}
},
"anyOf": [
{
"required": [
"style"
],
"properties": {
"style": {
"minLength": 1
}
}
},
{
"required": [
"lyrics"
],
"properties": {
"lyrics": {
"minLength": 1
}
}
},
{
"required": [
"negative_tags"
],
"properties": {
"negative_tags": {
"minLength": 1
}
}
}
]
},
"else": {
"properties": {
"prompt": {
"maxLength": 3000
}
},
"anyOf": [
{
"required": [
"style"
],
"properties": {
"style": {
"minLength": 1
}
}
},
{
"required": [
"lyrics"
],
"properties": {
"lyrics": {
"minLength": 1
}
}
},
{
"required": [
"image_urls"
],
"properties": {
"image_urls": {
"minItems": 1
}
}
},
{
"required": [
"audio_urls"
],
"properties": {
"audio_urls": {
"minItems": 1
}
}
},
{
"required": [
"video_urls"
],
"properties": {
"video_urls": {
"minItems": 1
}
}
}
],
"not": {
"anyOf": [
{
"required": [
"duration"
]
},
{
"required": [
"vocal_gender"
]
},
{
"required": [
"style_weight"
]
},
{
"required": [
"weirdness_constraint"
]
},
{
"required": [
"audio_weight"
]
},
{
"required": [
"variety"
]
}
]
}
}
},
{
"if": {
"properties": {
"instrumental": {
"const": true
}
},
"required": [
"instrumental"
]
},
"then": {
"not": {
"required": [
"audio_weight"
]
}
}
}
]
},
"Message": {
"type": "object",
"properties": {
"role": {
"enum": [
"system",
"developer",
"user",
"assistant",
"tool"
]
},
"content": {
"type": [
"string",
"array",
"null"
],
"description": "Строка или части text, image_url, video_url, input_audio. input_audio содержит format=mp3/wav и data=base64. Пустое/null содержимое допустимо у assistant с tool_calls."
},
"name": {
"type": "string"
},
"tool_call_id": {
"type": "string",
"description": "Обязателен при role=tool."
},
"tool_calls": {
"type": "array",
"items": {
"type": "object"
}
}
},
"required": [
"role"
]
},
"MediaSource": {
"type": "string",
"minLength": 1,
"description": "HTTPS URL публичного сервера или data URI base64. Ограничения формата, размера и хранения задаёт администратор. Частные адреса запрещены."
},
"Reference": {
"anyOf": [
{
"$ref": "#/components/schemas/MediaSource"
},
{
"type": "object",
"properties": {
"type": {
"enum": [
"image_url",
"video_url",
"audio_url"
]
},
"image_url": {
"anyOf": [
{
"$ref": "#/components/schemas/MediaSource"
},
{
"type": "object",
"properties": {
"url": {
"$ref": "#/components/schemas/MediaSource"
}
},
"required": [
"url"
]
}
]
},
"video_url": {
"anyOf": [
{
"$ref": "#/components/schemas/MediaSource"
},
{
"type": "object",
"properties": {
"url": {
"$ref": "#/components/schemas/MediaSource"
}
},
"required": [
"url"
]
}
]
},
"audio_url": {
"anyOf": [
{
"$ref": "#/components/schemas/MediaSource"
},
{
"type": "object",
"properties": {
"url": {
"$ref": "#/components/schemas/MediaSource"
}
},
"required": [
"url"
]
}
]
}
},
"required": [
"type"
]
}
],
"description": "Для изображений допускается только image_url. Видео может поддерживать video_url/audio_url."
},
"ChatResult": {
"type": "object",
"properties": {
"id": {
"$ref": "#/components/schemas/PublicId"
},
"model": {
"type": "string"
},
"usage": {
"$ref": "#/components/schemas/Usage"
},
"ai_service": {
"type": "object",
"properties": {
"request_id": {
"$ref": "#/components/schemas/PublicId"
},
"billing": {
"$ref": "#/components/schemas/Billing"
}
},
"required": [
"request_id",
"billing"
]
},
"choices": {
"type": "array",
"items": {
"type": "object",
"properties": {
"index": {
"type": "integer"
},
"message": {
"type": "object",
"properties": {
"role": {
"type": "string"
},
"content": {
"type": [
"string",
"null"
]
},
"audio": {
"$ref": "#/components/schemas/AudioResult"
}
},
"required": [],
"description": "role=assistant, content — текст/null; возможны tool_calls и images с файлами Formula AI. Завершённое аудио содержит собственный URL и параметры PCM16."
},
"finish_reason": {
"type": [
"string",
"null"
]
}
},
"required": [
"message"
]
}
}
},
"required": [
"id",
"model",
"ai_service",
"choices"
]
},
"ImageResult": {
"type": "object",
"properties": {
"id": {
"$ref": "#/components/schemas/PublicId"
},
"model": {
"type": "string"
},
"usage": {
"$ref": "#/components/schemas/Usage"
},
"ai_service": {
"type": "object",
"properties": {
"request_id": {
"$ref": "#/components/schemas/PublicId"
},
"billing": {
"$ref": "#/components/schemas/Billing"
}
},
"required": [
"request_id",
"billing"
]
},
"data": {
"type": "array",
"items": {
"type": "object",
"properties": {
"url": {
"type": "string"
},
"b64_json": {
"type": "string"
},
"revised_prompt": {
"type": "string"
}
},
"required": []
}
}
},
"required": [
"id",
"model",
"ai_service",
"data"
]
}
}
},
"externalDocs": {
"url": "https://formula-ai.ru/docs"
}
}Примеры cURL используют Bash. Задайте AI_SERVICE_API_KEY и AI_SERVICE_MODEL; модель выберите из /models. В PHP для опроса/файла задайте AI_SERVICE_REQUEST_ID/AI_SERVICE_MEDIA_ID, для правки — AI_SERVICE_SOURCE_URL. Для локального сертификата используйте доверенный CA через --cacert, для PHP — AI_SERVICE_CA. Проверку TLS сохраняйте включённой.