API-справочник
ID запроса — 32 шестнадцатеричных символа собственного сервиса. Деталь содержит id, object=ai_service.request, model, operation, status, created_at, finished_at, content_expires_at, content_expired, usage, billing, result, error.
Состояния: queued — очередь; running — выполнение; waiting — внешний результат; saving_media — сохранение; uncertain — результат уточняется; completed — результат готов; failed — ошибка; cancelled — отменённый запрос. uncertain не запускает слепую повторную генерацию.
billing содержит currency=RUB, charged/refunded как строки с 7 знаками, status=pending или confirmed. Финансовое ожидание отделено от состояния результата.
Списки /requests и /usage принимают page от 1 до 1000000, возвращают data и page; размер страницы 50. Содержат только историю владельца ключа. content_expired=true означает, что вход и результат очищены по сроку хранения; деньги и usage остаются.
Опрос GET /requests/{id} не резервирует деньги и не вызывает новую генерацию.
Если первоначальный ответ потерян, вызовите GET /requests/by-idempotency-key с Authorization: Bearer и прежним Idempotency-Key в заголовке. Ответ — тот же ai_service.request, включая id, status, result и billing. Ключ ищется в пределах клиента, даже через другой его действующий API-ключ. Неизвестный или чужой ключ — 404, отсутствующий или некорректный — 422. После очистки содержимого поиск сохраняет ID и финансовые метаданные. Пример: curl "https://formula-ai.ru/api/v1/requests/by-idempotency-key" -H "Authorization: Bearer $AI_SERVICE_API_KEY" -H "Idempotency-Key: example-text-1".
status описывает результат, billing.status — расчёты: completed может иметь billing.status=pending, а uncertain — подтверждённый расход без полного результата. Частичный result при uncertain не считается готовым. Нулевая предварительная запись без usage не подтверждает бесплатное завершение. После разрыва сервис восстанавливает сохранённый завершённый ответ или опрашивает ту же внешнюю задачу, если поставщик поддерживает получение результата. Если доступна только стоимость, uncertain сохраняется до появления доказательства результата; автоматическая новая генерация не выполняется.
POST /requests/{id}/cancel с Bearer и без тела отменяет собственный незавершённый запрос. Ответ HTTP 200 содержит статус cancelled; повторная отмена безопасна. Чужой или неизвестный запрос — 404, завершённый completed/failed — 409. До отправки поставщику генерация не создаётся. Для уже отправленного запроса активное HTTP/SSE-соединение прерывается воркером; внешняя остановка не гарантируется. Подтверждённая отмена поставщиком также даёт cancelled и error.code=provider_cancelled. Таймаут и пустые сведения поставщика сами по себе не доказывают отмену. Поздний результат не возобновляет отменённый запрос. Списание и возврат учитываются по фактическим данным, billing.status может оставаться pending.
cURL · GET /requests/REQUEST_ID
curl "https://formula-ai.ru/api/v1/requests/REQUEST_ID" \
-H "Authorization: Bearer $AI_SERVICE_API_KEY"
cURL · POST /requests/{id}/cancel
curl -X POST "https://formula-ai.ru/api/v1/requests/$AI_SERVICE_REQUEST_ID/cancel" \
-H "Authorization: Bearer $AI_SERVICE_API_KEY"
cURL · GET /requests?page=1
curl "https://formula-ai.ru/api/v1/requests?page=1" \
-H "Authorization: Bearer $AI_SERVICE_API_KEY"
PHP · GET /requests/
<?php
$key = getenv("AI_SERVICE_API_KEY");
$url = "https://formula-ai.ru/api/v1/requests/";
$url .= rawurlencode(getenv("AI_SERVICE_REQUEST_ID"));
$handle = curl_init($url);
curl_setopt_array($handle, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer " . $key],
]);
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 · GET /requests/
<?php
$key = getenv("AI_SERVICE_API_KEY");
$url = "https://formula-ai.ru/api/v1/requests/";
$url .= rawurlencode(getenv("AI_SERVICE_REQUEST_ID")) . "/cancel";
$handle = curl_init($url);
curl_setopt_array($handle, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer " . $key],
]);
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 · GET /requests?page=1
<?php
$key = getenv("AI_SERVICE_API_KEY");
$url = "https://formula-ai.ru/api/v1/requests?page=1";
$handle = curl_init($url);
curl_setopt_array($handle, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer " . $key],
]);
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": {
"/requests": {
"get": {
"operationId": "listRequests",
"summary": "История запросов",
"responses": {
"200": {
"description": "Собственные данные клиента.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Requests"
}
}
}
},
"default": {
"description": "Ошибка доступа или параметров.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
},
"parameters": [
{
"name": "page",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 1000000,
"default": 1
},
"description": "По 50 записей, от новых к старым."
}
]
}
},
"/usage": {
"get": {
"operationId": "listUsage",
"summary": "История использования",
"responses": {
"200": {
"description": "Собственные данные клиента.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Requests"
}
}
}
},
"default": {
"description": "Ошибка доступа или параметров.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
},
"parameters": [
{
"name": "page",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 1000000,
"default": 1
},
"description": "По 50 записей, от новых к старым."
}
]
}
},
"/requests/{id}": {
"get": {
"operationId": "getRequest",
"summary": "Состояние собственного запроса",
"responses": {
"200": {
"description": "Собственные данные клиента.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Request"
}
}
}
},
"default": {
"description": "Ошибка доступа или параметров.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"$ref": "#/components/schemas/PublicId"
}
}
]
}
},
"/requests/{id}/cancel": {
"post": {
"operationId": "cancelRequest",
"summary": "Отменить собственный незавершённый запрос",
"description": "Тело не требуется. Повторная отмена возвращает тот же cancelled. Отмена завершённого запроса — 409. До отправки поставщику генерация не создаётся; после отправки HTTP/SSE прерывается по сигналу воркера, внешняя остановка не гарантируется. Фактические расходы и возвраты продолжают сверяться; поздний результат не изменяет cancelled.",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"$ref": "#/components/schemas/PublicId"
}
}
],
"responses": {
"200": {
"description": "Запрос отменён в Formula AI. Проверьте billing.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Request"
}
}
}
},
"401": {
"description": "Неверный или отозванный ключ.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Запрос не найден у владельца ключа.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"409": {
"description": "Запрос уже завершён.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
}
},
"/requests/by-idempotency-key": {
"get": {
"operationId": "getRequestByIdempotencyKey",
"summary": "Найти исходную операцию по ключу клиента",
"responses": {
"200": {
"description": "Собственные данные клиента.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Request"
}
}
}
},
"default": {
"description": "Ошибка доступа или параметров.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
},
"parameters": [
{
"name": "Idempotency-Key",
"in": "header",
"required": true,
"schema": {
"type": "string",
"minLength": 1,
"maxLength": 191,
"pattern": "^[A-Za-z0-9._:\\-]+$"
},
"description": "Ключ исходного POST в пределах владельца Bearer. Чужой или неизвестный ключ — 404; отсутствующий или неверный — 422. Не создаёт запрос и возвращает метаданные даже после очистки содержимого."
}
]
}
}
},
"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"
]
},
"Requests": {
"type": "object",
"properties": {
"data": {
"type": "array",
"maxItems": 50,
"items": {
"$ref": "#/components/schemas/Request"
}
},
"page": {
"type": "integer",
"minimum": 1,
"maximum": 1000000
}
},
"required": [
"data",
"page"
]
},
"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"
]
}
}
},
"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 сохраняйте включённой.