Перейти к основному содержимому

Примеры подключения и использования

примечание

Базовый URL и API-ключ выдаются при подключении. Во всех примерах они подставляются через переменные BASE_URL и API_KEY — замените их на выданные вам значения.

Общие сведения о подключении — в разделе Инструкция по подключению, полный список моделей, маршрутов и цен — на странице Модели и поставщики.

export API_KEY="ваш_API_ключ"
export BASE_URL="https://<адрес, выданный при подключении>/v1"

Общие правила​

Во всех запросах обязательны заголовки:

ЗаголовокНазначение
Authorization: Bearer <ключ>API-ключ, выдаётся при подключении
X-AIN-USERNAMEИмя пользователя — для аналитики потребления
X-AIN-SOURCEIDИдентификатор вашей системы — для аналитики потребления

Маршрут всегда передаётся в поле model в теле запроса. Шлюз определяет модель именно по этому полю, а не по URL.

Суффикс маршрута подсказывает, по какому пути его вызывать. Маршрут, оканчивающийся на .chat_completions, отправляется на POST /chat/completions; на .audio_transcriptions — на путь транскрипции и так далее. Если отправить маршрут не на тот путь, шлюз вернёт ошибку. Точный путь по каждому маршруту указан в карточке модели на странице Модели и поставщики.

Список маршрутов, доступных вашему ключу:

curl -sS "$BASE_URL/models" \
-H "Authorization: Bearer $API_KEY" \
-H "X-AIN-USERNAME: ваш_логин" \
-H "X-AIN-SOURCEID: название_системы"

Ответ содержит только те маршруты, которые разрешены вашей лицензией. Если нужного маршрута в списке нет — обратитесь в поддержку.

Chat Completions​

Базовый сценарий для всех текстовых моделей. API совместим с OpenAI.

Python (httpx)​

import httpx

BASE_URL = "https://<адрес, выданный при подключении>/v1"
API_KEY = "ваш_API_ключ"

headers = {
"Authorization": f"Bearer {API_KEY}",
"X-AIN-USERNAME": "ваш_логин",
"X-AIN-SOURCEID": "название_системы",
}

client = httpx.Client(base_url=BASE_URL, headers=headers, timeout=120.0)

resp = client.post("/chat/completions", json={
"model": "opr.deepseek4_pro.chat_completions",
"messages": [{"role": "user", "content": "Привет! Расскажи о себе."}],
"max_tokens": 512,
"temperature": 0.7,
})
resp.raise_for_status()
print(resp.json()["choices"][0]["message"]["content"])

Python (openai SDK)​

from openai import OpenAI

client = OpenAI(
base_url="https://<адрес, выданный при подключении>/v1",
api_key="ваш_API_ключ",
default_headers={
"X-AIN-USERNAME": "ваш_логин",
"X-AIN-SOURCEID": "название_системы",
},
)

response = client.chat.completions.create(
model="opr.claude-sonnet4.6.chat_completions",
messages=[{"role": "user", "content": "Напиши краткое резюме статьи..."}],
)
print(response.choices[0].message.content)

Потоковый ответ​

stream = client.chat.completions.create(
model="opr.claude-sonnet4.6.chat_completions",
messages=[{"role": "user", "content": "Расскажи длинную историю."}],
stream=True,
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)

Protected-эндпоинты​

Маршруты с суффиксом .protected вызываются точно так же — меняется только значение model. Запрос дополнительно проходит через слой фильтрации контента.

resp = client.post("/chat/completions", json={
"model": "opr.claude-sonnet4.6.chat_completions.protected",
"messages": [{"role": "user", "content": "Текст с персональными данными..."}],
})

Генерация изображений​

Изображения генерируются по двум разным протоколам. Выбор протокола определяется суффиксом маршрута.

Суффикс маршрутаПротоколAPI-путь
.chat_completionsChat Completions/chat/completions
.imagesImage API/images

Протокол 1: через Chat Completions​

Так работают маршруты opr.nano-banana-2.chat_completions и opr.nano-banana-2-lite.chat_completions. Изображение возвращается внутри обычного chat-ответа.

Обязательное поле — modalities со значением ["image", "text"]. Без него модель вернёт только текст.

import base64
import httpx

BASE_URL = "https://<адрес, выданный при подключении>/v1"
API_KEY = "ваш_API_ключ"

headers = {
"Authorization": f"Bearer {API_KEY}",
"X-AIN-USERNAME": "ваш_логин",
"X-AIN-SOURCEID": "название_системы",
}

resp = httpx.post(
f"{BASE_URL}/chat/completions",
headers=headers,
json={
"model": "opr.nano-banana-2.chat_completions",
"messages": [{"role": "user", "content": "рыжий кот на диване, фотореализм"}],
"modalities": ["image", "text"],
"image_config": {"aspect_ratio": "16:9"},
},
timeout=300.0,
)
resp.raise_for_status()

# Изображение приходит как data-URL внутри message.images
url = resp.json()["choices"][0]["message"]["images"][0]["image_url"]["url"]
header, b64 = url.split(",", 1)
with open("output.png", "wb") as f:
f.write(base64.b64decode(b64))

Допустимые значения aspect_ratio: "1:1", "16:9", "9:16".

Протокол 2: через Image API​

Так работают маршруты opr.flux-2-pro.images, opr.flux-2-klein-4b.images, opr.seedream-4.5.images, opr.recraft-v4.images, opr.recraft-v4-vector.images, opr.gpt-image-2.images. Используется отдельный путь /images, поле prompt вместо messages.

curl -sS -X POST "$BASE_URL/images" \
-H "Authorization: Bearer $API_KEY" \
-H "X-AIN-USERNAME: ваш_логин" \
-H "X-AIN-SOURCEID: название_системы" \
-H "Content-Type: application/json" \
-d '{
"model": "opr.flux-2-pro.images",
"prompt": "рыжий кот на диване, фотореализм",
"aspect_ratio": "16:9",
"output_format": "png"
}'

Ответ:

{
"created": 1748372400,
"data": [
{
"b64_json": "<base64>",
"media_type": "image/png"
}
],
"usage": {
"prompt_tokens": 0,
"completion_tokens": 4175,
"total_tokens": 4175
}
}

Извлечение результата:

import base64
import httpx

resp = httpx.post(
f"{BASE_URL}/images",
headers=headers,
json={
"model": "opr.flux-2-pro.images",
"prompt": "рыжий кот на диване, фотореализм",
"aspect_ratio": "16:9",
"output_format": "png",
},
timeout=300.0,
)
resp.raise_for_status()

item = resp.json()["data"][0]
with open("output.png", "wb") as f:
f.write(base64.b64decode(item["b64_json"]))
print(item["media_type"])
примечание

Изображение возвращается внутри JSON в base64, поэтому ответ может весить 3–4 МБ. Ставьте таймаут не меньше 300 секунд.

Генерация видео​

Видео генерируется асинхронно, в три шага, и это отдельный протокол — не Chat Completions и не Image API.

ШагМетод и путьМаршрут в поле model
1. Отправка заданияPOST /videosopr.flux-3-video.videos
2. Опрос статусаPOST /videos/{job_id}opr.flux-3-video.videos_status
3. СкачиваниеPOST /videos/{job_id}/contentopr.flux-3-video.videos_content
warning

Все три шага — POST-запросы с JSON-телом, в котором указан маршрут.

Шлюз определяет маршрут по полю model в теле запроса, а не по URL. Поэтому опрос статуса и скачивание отправляются методом POST, с заголовком Content-Type: application/json и телом {"model": "..."}. Иначе запрос завершится ошибкой:

  • запрос отправлен методом GET → {"error": "nexus not found"}
  • в теле нет поля model или тело пустое ({}) → {"error": "nexus not found"}
  • есть Content-Type, но нет тела → unexpected end of JSON input

На каждом шаге указывается свой маршрут: .videos, .videos_status, .videos_content — это три разных nexus.

Шаг 1. Отправка задания​

curl -sS -X POST "$BASE_URL/videos" \
-H "Authorization: Bearer $API_KEY" \
-H "X-AIN-USERNAME: ваш_логин" \
-H "X-AIN-SOURCEID: название_системы" \
-H "Content-Type: application/json" \
-d '{
"model": "opr.flux-3-video.videos",
"prompt": "рыжий кот сидит на столе и спрыгивает на пол"
}'

Ответ:

{
"id": "RVVqCZGhmtQqUuLZ0RD8",
"status": "pending",
"generation_id": "gen-vid-1786110460-3Y9Z4eazO6HkLGfg6nYK"
}

Параметры генерации (длительность и разрешение) задаются платформой — см. раздел «Генерация видео» на странице Модели и поставщики. Указывать их в запросе не требуется.

Шаг 2. Опрос статуса​

curl -sS -X POST "$BASE_URL/videos/$JOB_ID" \
-H "Authorization: Bearer $API_KEY" \
-H "X-AIN-USERNAME: ваш_логин" \
-H "X-AIN-SOURCEID: название_системы" \
-H "Content-Type: application/json" \
-d '{"model": "opr.flux-3-video.videos_status"}'

Ответ при готовности:

{
"id": "RVVqCZGhmtQqUuLZ0RD8",
"status": "completed",
"usage": {"cost": 0.85}
}

Возможные значения status: pending, completed, failed.

warning

Вместе со статусом в ответе приходят служебные поля polling_url и unsigned_urls. Они ведут во внутреннюю инфраструктуру и вашим ключом AIaaS не открываются — вернётся 401 или 404. Скачивать результат нужно только через шлюз, шагом 3.

Шаг 3. Скачивание результата​

curl -sS -o output.mp4 \
-X POST "$BASE_URL/videos/$JOB_ID/content?index=0" \
-H "Authorization: Bearer $API_KEY" \
-H "X-AIN-USERNAME: ваш_логин" \
-H "X-AIN-SOURCEID: название_системы" \
-H "Content-Type: application/json" \
-d '{"model": "opr.flux-3-video.videos_content"}'

Ответ — бинарный mp4.

Полный цикл на Python​

import time
import httpx

BASE_URL = "https://<адрес, выданный при подключении>/v1"
API_KEY = "ваш_API_ключ"
MODEL = "opr.flux-3-video"

headers = {
"Authorization": f"Bearer {API_KEY}",
"X-AIN-USERNAME": "ваш_логин",
"X-AIN-SOURCEID": "название_системы",
"Content-Type": "application/json",
}

with httpx.Client(base_url=BASE_URL, headers=headers, timeout=300.0) as client:
# 1. Отправка задания
resp = client.post("/videos", json={
"model": f"{MODEL}.videos",
"prompt": "рыжий кот сидит на столе и спрыгивает на пол",
})
resp.raise_for_status()
job_id = resp.json()["id"]
print("job:", job_id)

# 2. Опрос статуса — POST с маршрутом в теле
for _ in range(40):
time.sleep(15)
resp = client.post(
f"/videos/{job_id}",
json={"model": f"{MODEL}.videos_status"},
)
resp.raise_for_status()
state = resp.json()
if state["status"] == "completed":
print("cost:", state.get("usage", {}).get("cost"))
break
if state["status"] == "failed":
raise RuntimeError(f"generation failed: {state}")
else:
raise TimeoutError("генерация не завершилась за отведённое время")

# 3. Скачивание
resp = client.post(
f"/videos/{job_id}/content",
params={"index": 0},
json={"model": f"{MODEL}.videos_content"},
)
resp.raise_for_status()
with open("output.mp4", "wb") as f:
f.write(resp.content)

Для Seedance замените значение MODEL на opr.seedance-2.0-fast — протокол идентичен.

Российские модели​

Российские модели доступны через тот же шлюз и тот же ключ, что и остальные. Отдельные учётные записи у вендоров, сертификаты российских удостоверяющих центров, сервисные аккаунты и получение временных токенов — всё это остаётся на стороне шлюза. Со стороны вашего приложения российская модель отличается от любой другой только идентификатором маршрута.

Оба семейства вызываются так же, как остальные chat-модели, — обычным запросом к /chat/completions:

СемействоПрефиксМаршруты
GigaChatsbr.sbr.gigachat-max.chat_completions, sbr.gigachat-pro.chat_completions, sbr.gigachat-lite.chat_completions
YandexGPT и Alice AIyndx.yndx.yandex-gpt-5.1-pro.chat_completions, yndx.yandex-gpt-5-pro.chat_completions, yndx.yandex-gpt-5-lite.chat_completions, yndx.alice-ai-llm.chat_completions
resp = client.post("/chat/completions", json={
"model": "yndx.yandex-gpt-5.1-pro.chat_completions",
"messages": [
{"role": "system", "content": "Отвечай кратко."},
{"role": "user", "content": "Привет!"},
],
})
resp.raise_for_status()
print(resp.json()["choices"][0]["message"]["content"])

Для GigaChat замените значение model, например на sbr.gigachat-pro.chat_completions: запрос и ответ устроены так же.

примечание

Маршрутов с окончанием .responses и пути /responses у моделей Яндекса больше нет. Если ваш код написан под них, замените маршрут на yndx.<модель>.chat_completions, путь — на /chat/completions, поле input — на массив messages, а ответ читайте из choices.

OCR — распознавание текста из документов​

Путь: POST /v1/v2/doc-to-text. Файл передаётся как multipart/form-data, маршрут — в поле формы model.

curl -sS -X POST "$BASE_URL/v2/doc-to-text" \
-H "Authorization: Bearer $API_KEY" \
-H "X-AIN-USERNAME: ваш_логин" \
-H "X-AIN-SOURCEID: название_системы" \
-F "model=itg.ocr.v2.doc-to-text" \
-F "file=@document.pdf"

Ответ:

{
"text": "Извлечённый текст документа..."
}
import httpx

with open("document.pdf", "rb") as f:
resp = httpx.post(
f"{BASE_URL}/v2/doc-to-text",
headers=headers,
data={"model": "itg.ocr.v2.doc-to-text"},
files={"file": ("document.pdf", f, "application/pdf")},
timeout=120.0,
)
resp.raise_for_status()
print(resp.json()["text"])

Остальные маршруты OCR (process-document, vlm-process, custom-process-text и другие) вызываются так же — меняются путь и значение model.

Конвертация документов (Docling)​

import httpx

with open("document.pdf", "rb") as f:
resp = httpx.post(
f"{BASE_URL}/v1/convert/file",
headers=headers,
data={"model": "itg.docling.convert_sync"},
files={"files": ("document.pdf", f, "application/pdf")},
timeout=300.0,
)
resp.raise_for_status()
print(resp.json())

Путь /v1/convert/file добавляется к базовому URL, который уже содержит /v1 — итоговый адрес выглядит как https://<адрес, выданный при подключении>/v1/v1/convert/file. Это не опечатка: первый /v1 — версия шлюза, второй — часть пути сервиса.

Транскрипция аудио (WhisperX)​

curl -sS -X POST "$BASE_URL/audio/transcriptions" \
-H "Authorization: Bearer $API_KEY" \
-H "X-AIN-USERNAME: ваш_логин" \
-H "X-AIN-SOURCEID: название_системы" \
-F "model=itg.whisperx-prod.audio_transcriptions" \
-F "file=@recording.mp3"
import httpx

with open("recording.mp3", "rb") as f:
resp = httpx.post(
f"{BASE_URL}/audio/transcriptions",
headers=headers,
data={"model": "itg.whisperx-prod.audio_transcriptions"},
files={"file": ("recording.mp3", f, "audio/mpeg")},
timeout=300.0,
)
resp.raise_for_status()
print(resp.json()["text"])

Синтез речи (TTS)​

import httpx

resp = httpx.post(
f"{BASE_URL}/audio/speech",
headers=headers,
json={
"model": "opr.gemini-3.1-flash-tts-preview.audio_speech",
"input": "Привет! Это тестовая генерация речи.",
"voice": "default",
},
timeout=120.0,
)
resp.raise_for_status()
with open("output.mp3", "wb") as f:
f.write(resp.content)

Ответ — бинарный аудиопоток. TTS тарифицируется по объёму сгенерированного аудио в байтах.

Embeddings и Reranker​

Векторизация​

resp = httpx.post(
f"{BASE_URL}/embeddings",
headers=headers,
json={
"model": "itg.qwen3-embedding-4b.embeddings",
"input": "Текст для векторизации",
},
timeout=60.0,
)
resp.raise_for_status()
print(resp.json()["data"][0]["embedding"][:8])

Внешние модели вызываются так же — достаточно поменять model на opr.voyage-4.embeddings или opr.gemini-embedding-2.embeddings. У всех embeddings-маршрутов тарифицируются только входящие токены.

Реранкинг​

Модель Qwen3-Reranker на маршруте itg.qwen3-reranker-4b.rerank отвечает на вопрос «подходит ли документ к запросу» и ждёт запрос и документы в своём формате. Без него оценки получаются почти одинаковыми. Оберните запрос и документы перед отправкой:

def wrap_qwen_rerank(query, docs, instruction="Given a web search query, retrieve relevant passages that answer the query"):
prefix = (
"<|im_start|>system\nJudge whether the Document meets the requirements based on the Query "
'and the Instruct provided. Note that the answer can only be "yes" or "no".<|im_end|>\n'
"<|im_start|>user\n"
)
suffix = "<|im_end|>\n<|im_start|>assistant\n<think>\n\n</think>\n\n"
wrapped_query = f"{prefix}<Instruct>: {instruction}\n<Query>: {query}\n"
wrapped_docs = [f"<Document>: {doc}{suffix}" for doc in docs]
return wrapped_query, wrapped_docs


docs = [
"Париж — столица и крупнейший город Франции.",
"Берлин стоит на реке Шпрее.",
"Завтра ожидается солнечная погода.",
]
query, documents = wrap_qwen_rerank("Какой город — столица Франции?", docs)

resp = httpx.post(
f"{BASE_URL}/rerank",
headers=headers,
json={
"model": "itg.qwen3-reranker-4b.rerank",
"query": query,
"documents": documents,
},
timeout=60.0,
)
resp.raise_for_status()
for r in sorted(resp.json()["results"], key=lambda r: r["relevance_score"], reverse=True):
print(f'{r["relevance_score"]:.4f}', docs[r["index"]])

Оценка — от 0 до 1: чем ближе к 1, тем лучше документ подходит к запросу. Инструкцию в instruction лучше писать по-английски и под свою задачу.

примечание

Обёртка нужна только маршруту itg.qwen3-reranker-4b.rerank. Маршруты opr.qwen3-reranker-8b.rerank и opr.rerank-2.5-lite.rerank вызываются без неё: запрос и документы передаются как есть. Повторная обёртка им не нужна.

Обнаружение персональных данных (PII)​

Сервис на базе GLiNER обнаруживает, маскирует и восстанавливает персональные данные в тексте.

ШагAPI-путьМаршрутОбязательные поля
Обнаружение/neritg.pii-detection.nertext
Маскирование/maskitg.pii-detection.masktext, entities
Восстановление/unmaskitg.pii-detection.unmasktext, mapping
warning

Маскирование выполняется в два шага. /mask принимает найденные сущности в поле entities — это результат вызова /ner. Вызов /mask без entities возвращает ошибку валидации 422.

Полный цикл​

import httpx

BASE_URL = "https://<адрес, выданный при подключении>/v1"
API_KEY = "ваш_API_ключ"

headers = {
"Authorization": f"Bearer {API_KEY}",
"X-AIN-USERNAME": "ваш_логин",
"X-AIN-SOURCEID": "название_системы",
}

text = "Иванов Иван Иванович, телефон +7-999-123-45-67, email ivanov@example.com"

with httpx.Client(base_url=BASE_URL, headers=headers, timeout=60.0) as client:
# 1. Найти персональные данные
resp = client.post("/ner", json={
"model": "itg.pii-detection.ner",
"text": text,
})
resp.raise_for_status()
ner = resp.json()

if not ner["contains_sensible_info"]:
print("персональных данных не найдено")

# 2. Замаскировать — entities передаются из ответа /ner как есть
resp = client.post("/mask", json={
"model": "itg.pii-detection.mask",
"text": text,
"entities": ner["entities"],
})
resp.raise_for_status()
mask = resp.json()

masked_text = mask["text"]
mapping = mask["mapping"]

# ... здесь masked_text отправляется в модель ...

# 3. Восстановить значения — mapping передаётся из ответа /mask как есть
resp = client.post("/unmask", json={
"model": "itg.pii-detection.unmask",
"text": masked_text,
"mapping": mapping,
})
resp.raise_for_status()
restored = resp.json()

print(restored["text"])

Что возвращают ручки​

/ner — найденные сущности с типом, границами и уверенностью:

{
"text": "Иванов Иван Иванович, телефон +7-999-123-45-67, email ivanov@example.com",
"entities": [
{"label": "PERSON_NAME", "start": 0, "end": 20, "score": 0.887},
{"label": "PHONE_NUMBER", "start": 30, "end": 46, "score": 0.973},
{"label": "EMAIL", "start": 54, "end": 72, "score": 0.985}
],
"contains_sensible_info": true,
"usage": {"input_tokens": 130}
}

/mask — обезличенный текст и словарь замен. Формат плейсхолдера — ***{N}_{LABEL}***:

{
"text": "***0_PERSON_NAME***, телефон ***1_PHONE_NUMBER***, email ***2_EMAIL***",
"mapping": {
"***0_PERSON_NAME***": "Иванов Иван Иванович",
"***1_PHONE_NUMBER***": "+7-999-123-45-67",
"***2_EMAIL***": "ivanov@example.com"
}
}

/unmask — текст с восстановленными значениями. Плейсхолдеры заменяются на исходные значения как есть: ***0_PERSON_NAME*** → Иванов Иван Иванович.

примечание

Поле usage возвращает только /ner. У /mask и /unmask его нет — это не ошибка: потребление всей цепочки считается по вызову детектора. У PII-маршрутов исходящие токены равны нулю, поскольку сервис возвращает разметку, а не сгенерированный текст.

Готовая прокси-обёртка, встраиваемая между приложением и моделью, описана в разделе Интеграция PII-прокси. Сравнение с protected-маршрутами — в разделе Protected-эндпоинты и защита персональных данных.

Перевод (DeepL)​

resp = httpx.post(
f"{BASE_URL}/translate",
headers=headers,
json={
"model": "ain.deepl.translate",
"text": "Hello world",
"source_lang": "EN",
"target_lang": "RU",
},
timeout=60.0,
)
resp.raise_for_status()
print(resp.json())

Рекомендуемые таймауты​

СценарийТаймаут
Chat Completions120 с
Генерация изображений300 с
Отправка задания на видео120 с
Скачивание видео300 с
OCR, Docling, транскрипция120–300 с в зависимости от размера файла
Embeddings, reranker, перевод60 с

Обработка ошибок​

Полный разбор ответов шлюза с рекомендациями — в разделе Ошибки и диагностика.

ОтветПричина
{"error": "nexus \"...\" not found"}Маршрут не существует или недоступен вашему ключу. Проверьте список через GET /models.
{"error": "unknown content-type"}Не передан заголовок Content-Type: application/json.
unexpected end of JSON inputОтсутствует тело запроса. Чаще всего — при опросе статуса или скачивании видео без тела {"model": "..."}.
{"error": "invalid endpoint"}Маршрут вызван по неподходящему пути — например, видео-маршрут через /chat/completions.
HTTP 401Неверный или неактивный API-ключ.