Сегодня многие разработчики различного уровня знают n8n как гибкий инструмент для автоматизации. В нем можно собрать почти любой сценарий - от простейшего Telegram-бота до сложных бизнес-процессов, используя множество готовых нод (узлов) для работы с популярными сервисами.
Но что делать, если в это множество не входит один из используемых вами сервисов, а через ноду HTTP Requests работать крайне сложно и неудобно? Или, может, хочется подключить собственный API и работать с ним по собственной логике?
Здесь напрашивается довольно простой ответ: написать свою ноду на n8n. Изначально это кажется сложным, однако, прочитав эту статью, вы сможете буквально за 1 вечер собрать минимально-рабочую ноду под ваши "хотелки".
Community nodes - что это?
Что очевидно из названия, это нода, написанная каким-то разработчиком из комьюнити (сообщества) n8n.
Комьюнити-ноды недоступны в списке нод в воркфлоу без предварительной их установки. Все ноды, которые доступны без дополнительных манипуляций, проверены и добавлены именно разработчиками n8n.
Такие ноды публикуются разработчиками как пакет в npm Registry, название которого обязательно начинается с n8n-nodes для того, чтобы n8n смог увидеть его.
Например:
n8n-nodes-amvera-inferenceилиn8n-nodes-my-first-node
Где можно развернуть n8n
Перед тем как писать свою ноду, нужно подготовить среду. n8n можно установить локально, в Docker, развернуть в облаке или на VDS/VPS.
В моём случае всё происходило в Amvera Cloud - сервисе для простого и быстрого развертывания IT-приложений, в котором n8n уже есть как настроенный сервис с бесплатным доменом, запуском "одной кнопкой" и собственной нодой доступа к LLM c оплатой в рублях.
Установка комьюнити-ноды
Первым делом необходимо убедиться, что ваша версия n8n и окружение поддерживает установку комьюнити-нод.
Если вы используете преднастроенный сервис в Amvera, дополнительно ничего настраивать не нужно и установка community nodes должна быть доступна в настройках n8n.


Если же таких нет - попробуйте обновить n8n или создать/изменить переменную окружения N8N_COMMUNITY_NODES_ENABLED в значении true.
Здесь можно установить любую комьюнити-ноду из списка.
Если при установке комьюнити-ноды n8n возвращает ошибку:
Error installing new package: Request failed with status 504,
Попробуйте установить ноду еще раз через несколько минут, это нормально.
Создаем свою ноду шаг за шагом
Итак, когда у нас готово все окружение, мы можем приступать к практической части.
Мы разберем нашу ноду n8n-nodes-amvera-inference, которая упрощает работу с Amvera LLM Inference API, отправляя запросы к API с определенным токеном и возвращая ответ в двух видах: RAW JSON и Ответ модели (только сам ответ).
Подготовка проекта
Важно понимать, что нода - обычный npm-пакет, но с особой структурой.
Официальный репозиторий для быстрого старта доступен на GitHub: https://github.com/n8n-io/n8n-nodes-starter
Структура проекта
Структура нашей ноды выглядит следующим образом:
n8n-nodes-amvera-inference
├── credentials
│ └── AmveraLlmApi.credentials.ts
├── index.ts
├── nodes
│ └── AmveraLlm.node.ts
├── package.json
└── tsconfig.json
package.json- можно полностью скопировать с официального репозитория n8n-nodes-starter. Важно изменить название пакета.tsconfig.json- для предложенной структуры выше будет выглядеть так:
{
"compilerOptions": {
"target": "ES2019",
"module": "commonjs",
"declaration": true,
"outDir": "dist",
"rootDir": ".",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
"resolveJsonModule": true
},
"include": ["nodes/**/*.ts", "credentials/**/*.ts"],
"exclude": ["node_modules", "dist"]
}
AmveraLlmApi.credentials.ts- содержит в себе описание Credentials, используемых для ноды, если она требует авторизацию на TypeScript.AmveraLlm.node.ts- основной код (логика) работы ноды. Чуть ниже будет его разбор на рабочем примере.index.ts- необязательный файл, содержащий в себе export всех модулей.
AmveraLlmApi.credentials.ts
import { ICredentialType, INodeProperties } from 'n8n-workflow';
export class AmveraLlmApi implements ICredentialType {
name = 'amveraLlmApi';
displayName = 'Amvera LLM API';
properties: INodeProperties[] = [
{
displayName: 'API Token', // имя, которое будет отображаться в n8n
name: 'apiToken', // имя, по которому мы будем общаться дальше в коде
type: 'string', // тип кредов
typeOptions: { password: true }, // доп. настройки
default: '', // значение по дефолту - пустое
required: true, // обязательно ли наличие кредов
description: 'Токен от модели LLM', // описание в UI n8n
},
];
}
Как и говорилось ранее - этот файл содержит в себе описание вида Credentials для того, чтобы n8n понимал, как формировать окно создания кредов.
AmveraLlm.node.ts
import {
IExecuteFunctions,
INodeExecutionData,
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';
export class AmveraLlm implements INodeType {
description: INodeTypeDescription = {
displayName: 'Amvera LLM', // отображаемое имя
name: 'amveraLlm', // имя для обращений в коде
group: ['transform'], // группа (тип) ноды
version: 1, // версия
description: 'Работа с Amvera LLM API', // описание
defaults: { name: 'Amvera LLM' }, // дефолтные значения
inputs: ['main'], // входные данные (из предыдущей ноды)
outputs: ['main'], // выходные данные (в следующую ноду)
credentials: [{ name: 'amveraLlmApi', required: true }], // какие креды используются. Здесь мы как раз пишем имя из созданного ранее файла.
properties: [ // Описание полей внутри ноды. У нас это: выбор модели, создание сообщений для LLM, выбор режима вывода
{
displayName: 'Model', // отображаемое имя настройки ноды
name: 'model', // внутреннее имя настройки ноды
type: 'options', // тип (options - выпадающий список)
options: [ // что можно выбрать {name, value}
{ name: 'llama8b', value: 'llama8b' },
{ name: 'llama70b', value: 'llama70b' },
{ name: 'gpt-4.1', value: 'gpt-4.1' },
{ name: 'gpt-5', value: 'gpt-5' },
],
default: 'llama8b', // значение по умолчанию
},
{
displayName: 'Messages',
name: 'messages',
type: 'fixedCollection', //
typeOptions: { multipleValues: true },
default: {},
options: [
{
name: 'message',
displayName: 'Message',
values: [
{
displayName: 'Role',
name: 'role',
type: 'options',
options: [
{ name: 'system', value: 'system' },
{ name: 'user', value: 'user' },
{ name: 'assistant', value: 'assistant' },
],
default: 'user',
},
{
displayName: 'Text',
name: 'text',
type: 'string',
default: '',
},
],
},
],
},
{
displayName: 'Режим вывода',
name: 'returnMode',
type: 'options',
options: [
{ name: 'Ответ модели', value: 'first' },
{ name: 'JSON', value: 'raw' },
],
default: 'first',
},
],
};
async execute(this: IExecuteFunctions): Promise {
const items = this.getInputData();
const output: INodeExecutionData[] = [];
const creds = await this.getCredentials('amveraLlmApi');
const token = creds.apiToken as string;
for (let i = 0; i < items.length; i++) {
const model = this.getNodeParameter('model', i) as string;
const messages = this.getNodeParameter('messages.message', i, []) as Array<{ role: string; text: string }>;
const mode = this.getNodeParameter('returnMode', i) as string;
const endpoint = model.startsWith('llama') ? 'llama' : 'gpt';
const body = { model, messages };
const res = await this.helpers.httpRequest({
method: 'POST',
url: `https://kong-proxy.yc.amvera.ru/api/v1/models/${endpoint}`,
headers: {
'X-Auth-Token': `Bearer ${token}`,
'Content-Type': 'application/json',
},
body,
json: true,
});
let answer = '';
if (model.startsWith('llama')) {
const result = res?.result;
if (result?.alternatives?.length) {
answer = result.alternatives[0]?.message?.text ?? '';
}
} else {
if (res?.choices?.length) {
answer = res.choices[0]?.message?.content ?? '';
}
}
if (mode === 'first') {
output.push({ json: { text: answer } });
} else {
output.push({ json: res });
}
}
return [output];
}
}
Здесь чуть сложнее, но все также шаблонно.
Первая часть кода
Содержит описание самой ноды для формирования в n8n. Значения большинства параметров описаны в комментариях в коде. Используя шаблон выше вы можете формировать подобные ноды.
Вторая часть кода - execute()
Всё, что происходит внутри метода execute(), - это реальная логика работы ноды.
n8n вызывает этот метод каждый раз, когда workflow доходит до твоей ноды.
В этот момент нода:
получает входные данные;
читает настройки из интерфейса;
делает запрос к API (или любое другое действие), описанное вами в коде;
формирует выходной JSON и передает его дальше.
Разберем метод подробнее.
1. Получаем входные данные
const items = this.getInputData();
const output: INodeExecutionData[] = [];
getInputData()возвращает массив объектов (JSON) от предыдущей ноды;output- пустой массив, куда мы будем складывать результаты.
n8n умеет работать с массивами данных - если предыдущая нода передала, например, 10 строк, execute() выполнится 10 раз в цикле.
2. Получаем креды и параметры
const creds = await this.getCredentials('amveraLlmApi');
const token = creds.apiToken as string;
getCredentials('amveraLlmApi')- достает токен, который пользователь ввел в Credentials ноды.
Дальше - параметры, которые пользователь задаёт в интерфейсе ноды:
const model = this.getNodeParameter('model', i) as string;
const messages = this.getNodeParameter('messages.message', i, []) as Array<{ role: string; text: string }>;
const mode = this.getNodeParameter('returnMode', i) as string;
Каждый вызов getNodeParameter() получает значение поля из properties (той самой секции в описании ноды).
i - индекс текущего элемента из входных данных (если их несколько).
3. Формируем запрос к API
const endpoint = model.startsWith('llama') ? 'llama' : 'gpt';
const body = { model, messages };
Здесь мы определяем, какой эндпоинт использовать - llama или gpt и формируем body запроса.
4. Отправляем HTTP-запрос
const res = await this.helpers.httpRequest({
method: 'POST',
url: `https://kong-proxy.yc.amvera.ru/api/v1/models/${endpoint}`,
headers: {
'X-Auth-Token': `Bearer ${token}`,
'Content-Type': 'application/json',
},
body,
json: true,
});
this.helpers.httpRequest- встроенный метод n8n для HTTP-запросов (автоматически обрабатывает JSON, ошибки, HTTPS). Короче говоря: удобно.В заголовок добавляется токен авторизации (
Bearer ${token}), который мы получили из кредов.json: trueговорит n8n автоматически парсить ответ как JSON.
5. Обрабатываем ответ
Amvera LLM API может вернуть результат в разных форматах - у LLaMA и GPT структура ответа отличается.
let answer = '';
if (model.startsWith('llama')) {
const result = res?.result;
if (result?.alternatives?.length) {
answer = result.alternatives[0]?.message?.text ?? '';
}
} else {
if (res?.choices?.length) {
answer = res.choices[0]?.message?.content ?? '';
}
}
Для моделей LLaMA ответ находится в
res.result.alternatives[0].message.text.Для GPT-моделей - в
res.choices[0].message.content.?? ''- оператор, который возвращает строку, если undefined.
6. Формируем выходной результат
if (mode === 'first') {
output.push({ json: { text: answer } });
} else {
output.push({ json: res });
}
Если выбран режим "Ответ модели", нода вернет только текст (удобно для чат-ботов).
Если выбран режим "JSON", в вывод попадёт весь ответ API
7. Возвращаем результат n8n
return [output];
С такими настройками выглядит следующим образом

Весь код ноды доступен на нашем Github
Публикация пакета
Если у вас уже готов код (т.е. вы настроили вид ноды и ее логику в execute()), пакет нужно опубликовать в npm.
Для этого нужно иметь аккаунт в npm и залогиниться через команду npm login, которая перенаправить вас в браузер для авторизации.
Еще раз убедитесь, что в package.json название пакета начинается с n8n-nodes.
После этого, проект необходимо собрать. Для этого пишем:
npm i
npm run build # если у вас есть скрипт build в package.json для компиляции TS
Если у вас появились папки node_modules и dist с скомпилированными js файлами, ваш пакет готов к публикации. Пишем:
npm publish --access public
Если все получилось правильно, пакет должен появиться и быть доступен в npm Registry.
Итог
Теперь вы можете подключить опубликованный пакет в n8n и пользоваться нодой в свое удовольствие.
На самом деле, написание нод для n8n, не такая уж сложная задача, как может казаться на первый взгляд. Достаточно лишь по шаблону заполнить описание ноды и описать логику в методе execute().
Таким образом вы можете подключить любой API буквально за вечер, что дает полную свободу.