n8n и свой LLM API: обходим ноду OpenAI через HTTP Request
Штатная нода OpenAI в n8n не показывает поля Base URL: в документации n8n у credential «OpenAI» задокументированы только API Key и Organization ID, а в списке параметров ноды «OpenAI Chat Model» поля Base URL нет вовсе. Гарантированный способ подключить свой шлюз — нода HTTP Request. Ниже — готовый JSON ноды и полный workflow, который вызывает go2llm и возвращает ответ вместе со стоимостью запроса.
Проверено живым запросом: нет. Инструкция составлена по документации n8n и по исходному коду n8n. Если что-то не сходится — напишите в @go2llm_support, поправим. Живым запросом у go2llm проверены только Claude Code и OpenCode. n8n относится к классу «клиент со своим base URL».
Источники: n8n — OpenAI credentials, n8n — OpenAI Chat Model node, n8n — HTTP Request node, n8n — HTTP Request credentials.
Дата публикации: 11 сентября 2026.
Почему нода OpenAI не даёт сменить base URL
Разберём честно, потому что в интернете на этот счёт три противоречащие версии.
Факт 1. Официальная документация n8n по credential «OpenAI» перечисляет ровно два поля: API Key и Organization ID. Base URL там не описан.
Факт 2. Официальная документация n8n по ноде OpenAI Chat Model перечисляет параметры Model, Use Responses API, Built-in Tools и опции Frequency Penalty, Maximum Number of Tokens, Presence Penalty, Sampling Temperature, Timeout, Max Retries, Top P. Опции Base URL в этом списке нет.
Факт 3. В исходном коде n8n опция Base URL у ноды LmChatOpenAi существует, но объявлена с displayOptions.hide для версий ноды >= 1.1. То есть на свежедобавленной ноде n8n её просто не рисует. Именно из-за этого пользователи пишут «поле пропало» и «поля никогда не было» одновременно — обе группы правы, каждая для своей версии ноды.
Факт 4. В credential openAiApi в исходниках n8n поле Base URL (внутреннее имя url, значение по умолчанию https://api.openai.com/v1) есть, и в рантайме оно подставляется как база запроса. Но в официальной документации n8n оно не описано, поведение зависит от версии, а список моделей нода всё равно подтягивает динамически.
Вывод. Опираться на недокументированное поле в проде — плохая идея. Нода HTTP Request даёт полный контроль над URL, заголовками и телом запроса и не ломается при обновлении n8n. Дальше — именно этот путь.
Что понадобится
- n8n (Cloud или self-hosted) с доступом к созданию credential.
- Ключ go2llm с префиксом
gk_sk_. При регистрации на баланс начисляется $1, минимальное пополнение — $1. - Эндпоинт:
POST https://go2llm.tech/v1/chat/completions(OpenAI Chat Completions) илиPOST https://go2llm.tech/v1/messages(Anthropic Messages). - Точный public ID модели:
curl https://go2llm.tech/v1/models— эндпоинт открыт без ключа.
Пошаговая настройка
Шаг 1. Создайте credential типа Header Auth
Нода HTTP Request в n8n поддерживает generic-credentials: Basic auth, Custom auth, Digest auth, Header auth, OAuth1 API, OAuth2 API, Query auth, Simplified Custom Auth. Нам нужен Header Auth — внутреннее имя типа httpHeaderAuth.
В n8n: Credentials → Add credential → Header Auth. Два поля:
- Name:
Authorization - Value:
Bearer gk_sk_ВАШ_КЛЮЧ
Назовите credential, например, go2llm Authorization header. Так ключ не попадёт в экспорт workflow.
Шаг 2. Добавьте ноду HTTP Request
Параметры ноды:
| Параметр n8n | Значение |
|---|---|
| Method | POST |
| URL | https://go2llm.tech/v1/chat/completions |
| Authentication | Generic Credential Type |
| Generic Auth Type | Header Auth |
| Credential for Header Auth | go2llm Authorization header |
| Send Body | включено |
| Body Content Type | JSON |
| Specify Body | Using JSON |
Шаг 3. Готовая JSON-конфигурация ноды
Вставьте это прямо на канву n8n (Ctrl+V по скопированному JSON):
{
"parameters": {
"method": "POST",
"url": "https://go2llm.tech/v1/chat/completions",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"contentType": "json",
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ model: 'claude-sonnet-5', max_tokens: 1024, stream: false, messages: [{ role: 'user', content: $json.prompt }] }) }}",
"options": {
"timeout": 120000,
"response": {
"response": {
"neverError": false,
"responseFormat": "json"
}
}
}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [440, 0],
"name": "go2llm — chat/completions",
"credentials": {
"httpHeaderAuth": {
"name": "go2llm Authorization header"
}
}
}
Два замечания по этому JSON. JSON.stringify(...) внутри выражения избавляет от ручного экранирования кавычек в пользовательском промпте — это главный источник ошибок 400 invalid_request. stream: false обязателен: нода HTTP Request в n8n возвращает целый ответ и не собирает SSE-поток по кускам.
Шаг 4. Полный рабочий workflow
Импортируйте целиком через Workflows → Import from clipboard:
{
"name": "go2llm — минимальный вызов",
"nodes": [
{
"parameters": {},
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [0, 0],
"name": "Запуск вручную"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "p1",
"name": "prompt",
"value": "Ответь одним словом: работает",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [220, 0],
"name": "Промпт"
},
{
"parameters": {
"method": "POST",
"url": "https://go2llm.tech/v1/chat/completions",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"contentType": "json",
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ model: 'claude-sonnet-5', max_tokens: 1024, stream: false, messages: [{ role: 'user', content: $json.prompt }] }) }}",
"options": {
"timeout": 120000,
"response": {
"response": {
"neverError": false,
"responseFormat": "json"
}
}
}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [440, 0],
"name": "go2llm — chat/completions",
"credentials": {
"httpHeaderAuth": {
"name": "go2llm Authorization header"
}
}
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "r1",
"name": "answer",
"value": "={{ $json.choices[0].message.content }}",
"type": "string"
},
{
"id": "r2",
"name": "cost_usd",
"value": "={{ $json.usage.cost_usd }}",
"type": "string"
},
{
"id": "r3",
"name": "model",
"value": "={{ $json.model }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [660, 0],
"name": "Разобрать ответ"
}
],
"connections": {
"Запуск вручную": {
"main": [[{ "node": "Промпт", "type": "main", "index": 0 }]]
},
"Промпт": {
"main": [[{ "node": "go2llm — chat/completions", "type": "main", "index": 0 }]]
},
"go2llm — chat/completions": {
"main": [[{ "node": "Разобрать ответ", "type": "main", "index": 0 }]]
}
},
"settings": {},
"pinData": {}
}
После импорта откройте ноду go2llm — chat/completions и выберите в поле credential созданный на шаге 1 Header Auth — id credential в чужом экспорте не переносится.
Шаг 5 (опция). Нативный Anthropic Messages
go2llm отдаёт /v1/messages без прослойки-конвертера. Для этого варианта в ноде HTTP Request поменяйте URL на https://go2llm.tech/v1/messages, а в credential Header Auth используйте x-api-key вместо Authorization, плюс добавьте в Send Headers пару anthropic-version = 2023-06-01. Тело:
={{ JSON.stringify({ model: 'claude-sonnet-5', max_tokens: 1024, messages: [{ role: 'user', content: $json.prompt }] }) }}
Проверка, что заработало
Сначала вне n8n, чтобы отделить проблему ключа от проблемы ноды:
curl https://go2llm.tech/v1/chat/completions \
-H "Authorization: Bearer gk_sk_ВАШ_КЛЮЧ" \
-H "content-type: application/json" \
-d '{"model":"claude-sonnet-5","max_tokens":120,"messages":[{"role":"user","content":"Ответь одним словом: работает"}]}'
Ожидаемый результат: HTTP 200 и JSON, где choices[0].message.content — «работает», а в usage есть cost_usd.
Теперь в n8n нажмите Test workflow. На выходе ноды «Разобрать ответ» должны появиться три поля: answer = «работает», cost_usd — число вроде 0.000042, model = claude-sonnet-5. Поле cost_usd — это фактическое списание за конкретный вызов, его удобно писать в таблицу и считать стоимость сценария.
Какую модель выбрать
Актуальные ставки по каждой модели — на странице цен и в GET /api/pricing.
| Модель | Типичный сценарий в n8n |
|---|---|
gpt-5.6-luna | Классификация тикетов, теги, роутинг |
deepseek-v4-flash | Массовая обработка строк в цикле |
glm-5.3-flash | Суммаризация писем и заявок |
claude-haiku-4-5 | Извлечение полей из текста |
claude-sonnet-5 | Генерация писем, сложные правила |
gpt-5.6-sol | Рассуждающие шаги в сценарии |
В n8n вы чаще всего гоняете одинаковый системный промпт по сотням элементов, поэтому смотрите на цену входа и выхода, а не на кэш. Полный прайс — go2llm.tech/pricing.
Если не работает
- 401
no-key. В credential Header Auth в поле Value должно бытьBearer gk_sk_…— с префиксомBearerи пробелом. Без него шлюз ключ не увидит. - 400
invalid_request. Кавычки в промпте сломали JSON. ИспользуйтеJSON.stringify(...)вjsonBody, как в примере выше, а не ручную склейку строк. - 404
model_not_found. ID модели не из каталога. Скопируйте точныйidизcurl https://go2llm.tech/v1/models. - 404 на
/v1/responses. Вы указали URL Responses API. У go2llm этот эндпоинт не опубликован — используйте/v1/chat/completionsили/v1/messages. - 429
rate_limit. Лимит по умолчанию — 20 RPM на ключ. Workflow с циклом по 500 строкам выбивает его мгновенно. Включите в опциях ноды Batching: задайте Items per Batch и Batch Interval (в миллисекундах), чтобы держаться под 20 запросами в минуту. - 402
insufficient_balance. Пополните баланс (минимум $1) или уменьшитеmax_tokens. Баланс не уходит ниже нуля: шлюз резервирует оценку до вызова и списывает фактическую стоимость. - 502
upstream_unavailable. Поставщик недоступен. Безопасный текстовый запрос можно повторить с задержкой; для этого в n8n есть Retry On Fail в настройках ноды.
Разбор всех кодов — go2llm.tech/docs/errors.
FAQ
Можно ли подключить go2llm к ноде AI Agent в n8n? Нода AI Agent требует sub-ноду типа Chat Model, а HTTP Request такой sub-нодой быть не может. Остаются два варианта: собрать цикл агента вручную из HTTP Request и IF-нод, либо попробовать недокументированное поле Base URL в credential openAiApi. Второй путь мы живым запросом не проверяли и не утверждаем ни что он работает, ни что не работает: поведение поля Base URL меняется от версии к версии n8n, а конкретную версию мы не тестировали. Проверяемый на сегодня вариант — HTTP Request.
Почему не работает стриминг ответа? Нода HTTP Request отдаёт ответ целиком после завершения запроса и не разбирает SSE. Поэтому в теле стоит stream: false. Отдельно: go2llm может использовать fallback-маршрут до начала ответа, но после первого валидного SSE-события переключение уже не выполняется.
Как считать расходы по сценарию? go2llm возвращает usage.cost_usd в каждом ответе, в том числе в финальном usage-блоке SSE-стрима. Складывайте это поле в таблицу — получите точную себестоимость workflow без разбора токенов.
Что дальше
Подключение кодинг-агентов и редакторов — в хабе go2llm.tech/docs/coding-tools. Эндпоинты, лимиты, форматы ошибок и приватность — go2llm.tech/docs.