UNPKG

n8n-nodes-keitaro

Version:

Полноценная интеграция с Keitaro Tracker API для n8n

2,242 lines (2,196 loc) 102 kB
/* eslint-disable no-unused-vars */ import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription, IDataObject, GenericValue, } from 'n8n-workflow'; interface KeitaroError extends Error { config?: { url?: string; }; response?: { status?: number; statusText?: string; data?: unknown; }; } interface KeitaroResponse { status?: string | number; error?: string; message?: string; data?: unknown; response?: unknown; result?: unknown; body?: unknown; statusCode?: number; statusMessage?: string; } // Базовый интерфейс для всех сущностей Keitaro interface KeitaroEntity { id: number; created_at?: string; updated_at?: string; } // Интерфейс для кампании interface KeitaroCampaign extends KeitaroEntity { alias: string; name: string; type: string; uniqueness_method: string; cookies_ttl: number; position: number; state: string; cost_type: string; cost_value: number; cost_currency: string; group_id: number; bind_visitors: string; traffic_source_id: number; token: string; cost_auto: boolean; domain_id: number; notes: string; parameters: Record<string, { name: string; placeholder: string; alias?: string; }>; uniqueness_use_cookies: boolean; traffic_loss: number; domain: string; postbacks: unknown[]; group: string; } // Интерфейс для потока interface KeitaroStream extends KeitaroEntity { name: string; campaign_id: number; position: number; state: string; weight: number; offers: unknown[]; landings: unknown[]; filters: unknown[]; action_options: unknown; schema: string; type: string; comments?: string; } // Интерфейс для лендинга interface KeitaroLanding extends KeitaroEntity { name: string; url: string; state: string; group_id: number; archived: boolean; notes?: string; } // Интерфейс для оффера interface KeitaroOffer extends KeitaroEntity { name: string; url: string; state: string; group_id: number; payout: number; payout_auto: boolean; payout_type: string; payout_currency: string; archived: boolean; notes?: string; } // Интерфейс для трафика interface KeitaroTraffic extends KeitaroEntity { ip: string; user_agent: string; referrer?: string; language?: string; country?: string; region?: string; city?: string; browser_name?: string; browser_version?: string; os_name?: string; os_version?: string; device_type?: string; device_brand?: string; device_model?: string; } // Интерфейс для пользователя interface KeitaroUser extends KeitaroEntity { login: string; email: string; password?: string; name: string; status: string; role: string; receive_reports: boolean; } // Интерфейс для записи в блэклисте interface KeitaroBlacklist extends KeitaroEntity { value: string; type: string; comment?: string; } // Интерфейс для бота interface KeitaroBot extends KeitaroEntity { name: string; criteria: unknown[]; comment?: string; } // Интерфейс для постбэка interface KeitaroPostback extends KeitaroEntity { name: string; url: string; status: string; trigger: string; campaigns: number[]; networks: number[]; countries: string[]; sending_status?: string; sending_errors?: string[]; last_sent_at?: string; // Новые поля для поддержки всех параметров постбека postback_key?: string; lead_status?: string[]; sale_status?: string[]; rejected_status?: string[]; reg_status?: string[]; // Поддержка новых статусов для Keitaro 10.3+ dep_status?: string[]; // Поддержка новых статусов для Keitaro 10.3+ currency?: string; parameters?: { subid?: string; status?: string; payout?: number; currency?: string; click_id?: string; transaction_id?: string; cost?: number; // Стоимость конверсии tid?: string; // ID транзакции для upsell/rebill ignore_status?: string[]; // Статусы, которые нужно игнорировать return?: string; // Сообщение об успехе [key: string]: unknown; }; headers?: Record<string, string>; method?: 'GET' | 'POST'; timeout?: number; retry_count?: number; retry_delay?: number; } // Интерфейс для источника interface KeitaroSource extends KeitaroEntity { name: string; postback_url?: string; template?: string; parameters?: Record<string, unknown>; } // Интерфейс для конверсии interface KeitaroConversion extends KeitaroEntity { click_id: string; session_id?: number; action_id?: number; stream_id?: number; campaign_id?: number; landing_id?: number; offer_id?: number; revenue?: number; cost?: number; currency?: string; status?: string; conversion_status?: string; declined_reason?: string; sub_id_1?: string; sub_id_2?: string; sub_id_3?: string; sub_id_4?: string; sub_id_5?: string; transaction_id?: string; comment?: string; } // Интерфейс для домена interface KeitaroDomain extends KeitaroEntity { name: string; campaign_ids: number[]; ssl: boolean; redirect_type: string; comments?: string; } // Интерфейс для клика interface KeitaroClick extends KeitaroEntity { // Базовые поля клика campaign_id: number; stream_id: number; landing_id?: number; offer_id?: number; // Информация о стоимости и доходе cost?: number; revenue?: number; currency?: string; // Параметры трафика keyword?: string; source?: string; sub_id_1?: string; sub_id_2?: string; sub_id_3?: string; sub_id_4?: string; sub_id_5?: string; sub_id_6?: string; sub_id_7?: string; sub_id_8?: string; sub_id_9?: string; sub_id_10?: string; sub_id_11?: string; // Технические параметры is_bot?: boolean; is_unique?: boolean; is_conversion?: boolean; conversion_status?: string; conversions_count?: number; // Информация о посетителе ip?: string; user_agent?: string; language?: string; referrer?: string; // Гео-данные country?: string; region?: string; city?: string; // Информация об устройстве browser_name?: string; browser_version?: string; os_name?: string; os_version?: string; device_type?: string; device_brand?: string; device_model?: string; is_mobile?: boolean; is_tablet?: boolean; is_desktop?: boolean; // Сетевая информация isp?: string; connection_type?: string; ip_type?: string; // Ссылки и перенаправления original_url?: string; landing_url?: string; offer_url?: string; // Прочие поля browser?: string; os?: string; comment?: string; session_id?: string; } // Интерфейс для фильтра interface KeitaroFilter extends KeitaroEntity { name: string; state: string; conditions: unknown[]; mode: string; } // Интерфейс для настроек interface KeitaroSettings extends KeitaroEntity { key: string; value: unknown; } // Интерфейс для лога interface KeitaroLog extends KeitaroEntity { type: string; message: string; details?: unknown; } // Интерфейс для статистики interface KeitaroStats { date: string; clicks: number; unique_clicks: number; leads: number; conversions: number; revenue: number; cost: number; profit: number; cr: number; roi: number; epc: number; cpc: number; impressions?: number; ctr?: number; } // Интерфейс для группы interface KeitaroGroup extends KeitaroEntity { name: string; type: string; } // Функция для определения типа данных на основе ресурса function getTypedResponse(resource: string, data: unknown): unknown { switch (resource) { case 'campaign': return data as KeitaroCampaign; case 'stream': return data as KeitaroStream; case 'landing': return data as KeitaroLanding; case 'offer': return data as KeitaroOffer; case 'traffic': return data as KeitaroTraffic; case 'user': return data as KeitaroUser; case 'blacklist': return data as KeitaroBlacklist; case 'bot': return data as KeitaroBot; case 'postback': return data as KeitaroPostback; case 'source': return data as KeitaroSource; case 'conversion': return data as KeitaroConversion; case 'domain': return data as KeitaroDomain; case 'click': return data as KeitaroClick; case 'filter': return data as KeitaroFilter; case 'settings': return data as KeitaroSettings; case 'log': return data as KeitaroLog; case 'stats': return data as KeitaroStats; case 'group': return data as KeitaroGroup; default: return data; } } // Функция для определения типа ответа function getResponseData(response: KeitaroResponse): unknown { // Проверяем разные форматы ответа API Keitaro if (response && typeof response === 'object') { // Проверяем поле status для определения успешности запроса if ('status' in response) { // Если статус не "success", выбрасываем ошибку if (response.status !== 'success' && response.status !== 200) { const errorMessage = response.error || response.message || 'Неизвестная ошибка API'; throw new Error(`Ошибка API: ${errorMessage}`); } } if ('data' in response && response.data !== undefined) { return response.data; } else if ('response' in response && response.response !== undefined) { return response.response; } else if ('result' in response && response.result !== undefined) { return response.result; } else if ('body' in response && response.body !== undefined) { return response.body; } } // Если не удалось найти данные в известных полях, возвращаем весь ответ return response; } // Функция для безопасного логирования объектов function safeStringify(obj: unknown): string { try { return JSON.stringify(obj, (key, value) => { // Исключаем циклические ссылки if (key === 'socket' || key === '_httpMessage' || key === 'req' || key === 'res') { return '[Circular]'; } return value; }, 2); } catch (error) { return `[Не удалось сериализовать объект: ${error instanceof Error ? error.message : String(error)}]`; } } // Хелпер для создания пути API function getApiPath(resourceMap: Record<string, string>, resource: string, resourceId?: string, operation?: string): string { // Специальная обработка для клика с операцией getAll - используем /clicks/log if (resource === 'click' && operation === 'getAll') { return '/admin_api/v1/clicks/log'; } // Специальная обработка для конверсий с операцией getAll - используем /conversions/log if (resource === 'conversion' && operation === 'getAll') { return '/admin_api/v1/conversions/log'; } // Специальная обработка для статистики if (resource === 'stats' && operation === 'getAll') { return '/admin_api/v1/report/build'; } // Специальная обработка для конверсий if (resource === 'conversion') { return `/admin_api/v1/conversions${resourceId ? `/${resourceId}` : ''}`; } const resourcePath = resourceMap[resource]; if (!resourcePath) { throw new Error(`Неизвестный ресурс: ${resource}`); } return `/admin_api/v1/${resourcePath}${resourceId ? `/${resourceId}` : ''}`; } // Хелпер для форматирования URL API function formatBaseUrl(domain: string): string { let baseUrl = domain.trim(); // Удаляем завершающий слеш, если он есть if (baseUrl.endsWith('/')) { baseUrl = baseUrl.slice(0, -1); } // Добавляем протокол, если его нет if (!baseUrl.startsWith('http://') && !baseUrl.startsWith('https://')) { baseUrl = `https://${baseUrl}`; } return baseUrl; } export class Keitaro implements INodeType { description: INodeTypeDescription = { displayName: 'Keitaro', name: 'keitaro', icon: 'file:keitaro.svg', group: ['transform'], version: 1, subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', description: 'Работа с API Keitaro', defaults: { name: 'Keitaro', }, inputs: ['main'], outputs: ['main'], credentials: [ { name: 'keitaroApi', required: true, }, ], requestDefaults: { baseURL: '={{$credentials.domain}}', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', }, }, properties: [ { displayName: 'Ресурс', name: 'resource', type: 'options', noDataExpression: true, required: true, options: [ { name: 'Кампания', value: 'campaign', }, { name: 'Поток', value: 'stream', }, { name: 'Лендинг', value: 'landing', }, { name: 'Оффер', value: 'offer', }, { name: 'Трафик', value: 'traffic', }, { name: 'Пользователь', value: 'user', }, { name: 'Блэклист', value: 'blacklist', }, { name: 'Бот', value: 'bot', }, { name: 'Постбэк', value: 'postback', }, { name: 'Источник', value: 'source', }, { name: 'Конверсия', value: 'conversion', }, { name: 'Домен', value: 'domain', }, { name: 'Клик', value: 'click', }, { name: 'Фильтр', value: 'filter', }, { name: 'Настройки', value: 'settings', }, { name: 'Лог', value: 'log', }, { name: 'Статистика', value: 'stats', }, { name: 'Группа', value: 'group', }, ], default: 'campaign', description: 'Тип ресурса для работы', }, { displayName: 'Операция', name: 'operation', type: 'options', noDataExpression: true, required: true, displayOptions: { show: { resource: [ 'campaign', 'stream', 'landing', 'offer', 'traffic', 'user', 'blacklist', 'bot', 'postback', 'source', 'conversion', 'domain', 'click', 'filter', 'settings', 'log', 'stats', 'group', ], }, }, options: [ { name: 'Получить', value: 'get', description: 'Получить информацию', action: 'Получить информацию', }, { name: 'Получить Все', value: 'getAll', description: 'Получить список всех записей', action: 'Получить список всех записей', }, { name: 'Создать', value: 'create', description: 'Создать новую запись', action: 'Создать новую запись', }, { name: 'Обновить', value: 'update', description: 'Обновить существующую запись', action: 'Обновить существующую запись', }, { name: 'Удалить', value: 'delete', description: 'Удалить запись', action: 'Удалить запись', }, { name: 'Тестировать', value: 'test', description: 'Тестировать постбэк (отправить тестовую конверсию)', action: 'Тестировать постбэк', displayOptions: { show: { resource: [ 'postback', ], }, }, }, ], default: 'get', }, { displayName: 'ID Кампании', name: 'campaignId', type: 'string', required: true, displayOptions: { show: { resource: ['campaign'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID кампании', }, { displayName: 'Данные Кампании', name: 'campaignData', type: 'json', required: true, displayOptions: { show: { resource: ['campaign'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные кампании в формате JSON', }, { displayName: 'ID Потока', name: 'streamId', type: 'string', required: true, displayOptions: { show: { resource: ['stream'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID потока', }, { displayName: 'Данные Потока', name: 'streamData', type: 'json', required: true, displayOptions: { show: { resource: ['stream'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные потока в формате JSON', }, { displayName: 'ID Лендинга', name: 'landingId', type: 'string', required: true, displayOptions: { show: { resource: ['landing'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID лендинга', }, { displayName: 'Данные Лендинга', name: 'landingData', type: 'json', required: true, displayOptions: { show: { resource: ['landing'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные лендинга в формате JSON', }, { displayName: 'ID Оффера', name: 'offerId', type: 'string', required: true, displayOptions: { show: { resource: ['offer'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID оффера', }, { displayName: 'Данные Оффера', name: 'offerData', type: 'json', required: true, displayOptions: { show: { resource: ['offer'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные оффера в формате JSON', }, { displayName: 'ID Пользователя', name: 'userId', type: 'string', required: true, displayOptions: { show: { resource: ['user'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID пользователя', }, { displayName: 'Данные Пользователя', name: 'userData', type: 'json', required: true, displayOptions: { show: { resource: ['user'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные пользователя в формате JSON', }, { displayName: 'ID Блэклиста', name: 'blacklistId', type: 'string', required: true, displayOptions: { show: { resource: ['blacklist'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID записи в блэклисте', }, { displayName: 'Данные Блэклиста', name: 'blacklistData', type: 'json', required: true, displayOptions: { show: { resource: ['blacklist'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные записи в блэклисте в формате JSON', }, { displayName: 'ID Бота', name: 'botId', type: 'string', required: true, displayOptions: { show: { resource: ['bot'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID бота', }, { displayName: 'Данные Бота', name: 'botData', type: 'json', required: true, displayOptions: { show: { resource: ['bot'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные бота в формате JSON', }, { displayName: 'ID Постбэка', name: 'postbackId', type: 'string', required: true, displayOptions: { show: { resource: ['postback'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID постбэка', }, { displayName: 'Название постбэка', name: 'postbackName', type: 'string', required: true, displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], }, }, default: '', description: 'Название постбэка', }, { displayName: 'URL постбэка', name: 'postbackUrl', type: 'string', required: true, displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], }, }, default: '', placeholder: 'https://example.com/postback?clickid={sub_id_1}&status={status}', description: 'URL для отправки постбэка. Можно использовать макросы: {sub_id_1}, {status}, {revenue}, и т.д.', }, { displayName: 'Статус', name: 'postbackStatus', type: 'options', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], }, }, options: [ { name: 'Активный', value: 'active', }, { name: 'Неактивный', value: 'inactive', }, ], default: 'active', description: 'Статус постбэка', }, { displayName: 'Триггер', name: 'postbackTrigger', type: 'options', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], }, }, options: [ { name: 'Конверсия', value: 'conversion', description: 'Срабатывает при любой конверсии', }, { name: 'Лид', value: 'lead', description: 'Срабатывает только при получении лида', }, { name: 'Продажа', value: 'sale', description: 'Срабатывает только при продаже', }, ], default: 'conversion', description: 'Когда отправлять постбэк', }, { displayName: 'HTTP метод', name: 'postbackMethod', type: 'options', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], }, }, options: [ { name: 'GET', value: 'GET', }, { name: 'POST', value: 'POST', }, ], default: 'GET', description: 'HTTP метод для отправки постбэка', }, { displayName: 'Статусы лидов', name: 'leadStatus', type: 'string', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], }, }, default: 'lead,registration,new', description: 'Статусы для лидов, перечисленные через запятую. Если партнерская сеть отправит один из этих статусов, Keitaro запишет его как "Лид".', }, { displayName: 'Статусы продаж', name: 'saleStatus', type: 'string', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], }, }, default: 'sale,paid,billed,completed', description: 'Статусы для продаж, перечисленные через запятую. Если партнерская сеть отправит один из этих статусов, Keitaro запишет его как "Продажа".', }, { displayName: 'Отклоненные статусы', name: 'rejectedStatus', type: 'string', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], }, }, default: 'rejected,canceled,fake,fraud', description: 'Статусы для отклоненных конверсий, перечисленные через запятую. Если партнерская сеть отправит один из этих статусов, Keitaro запишет его как "Отклонено".', }, { displayName: 'Дополнительные настройки', name: 'postbackAdvanced', type: 'boolean', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], }, }, default: false, description: 'Показать дополнительные настройки постбэка', }, { displayName: 'Ключ постбэка', name: 'postbackKey', type: 'string', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], postbackAdvanced: [true], }, }, default: '', description: 'Ключ для аутентификации постбэка. Обеспечивает дополнительную безопасность.', }, { displayName: 'Валюта', name: 'postbackCurrency', type: 'string', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], postbackAdvanced: [true], }, }, default: 'USD', description: 'Валюта, используемая по умолчанию для конверсий.', }, { displayName: 'Таймаут (сек)', name: 'postbackTimeout', type: 'number', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], postbackAdvanced: [true], }, }, default: 30, description: 'Таймаут отправки постбэка в секундах.', }, { displayName: 'Количество повторных попыток', name: 'postbackRetryCount', type: 'number', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], postbackAdvanced: [true], }, }, default: 3, description: 'Сколько раз пытаться повторно отправить постбэк в случае ошибки.', }, { displayName: 'Задержка между попытками (сек)', name: 'postbackRetryDelay', type: 'number', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], postbackAdvanced: [true], }, }, default: 60, description: 'Задержка между повторными попытками в секундах.', }, { displayName: 'Кампании', name: 'postbackCampaigns', type: 'string', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], postbackAdvanced: [true], }, }, default: '', description: 'ID кампаний через запятую, для которых будет отправляться постбэк. Оставьте пустым для всех кампаний.', }, { displayName: 'Страны', name: 'postbackCountries', type: 'string', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], postbackAdvanced: [true], }, }, default: '', description: 'Коды стран через запятую, для которых будет отправляться постбэк. Оставьте пустым для всех стран.', }, { displayName: 'ID Источника', name: 'sourceId', type: 'string', required: true, displayOptions: { show: { resource: ['source'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID источника', }, { displayName: 'Данные Источника', name: 'sourceData', type: 'json', required: true, displayOptions: { show: { resource: ['source'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные источника в формате JSON', }, { displayName: 'ID Конверсии', name: 'conversionId', type: 'string', required: true, displayOptions: { show: { resource: ['conversion'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID конверсии', }, { displayName: 'Данные Конверсии', name: 'conversionData', type: 'json', required: true, displayOptions: { show: { resource: ['conversion'], operation: ['create', 'update'], }, }, default: '{"click_id":"CLICK_ID_HERE","status":"lead","revenue":0}', description: 'Данные конверсии в формате JSON. Обязательно укажите click_id.', }, { displayName: 'Упрощенное создание конверсии', name: 'conversionSimple', type: 'fixedCollection', typeOptions: { multipleValues: false, }, displayOptions: { show: { resource: ['conversion'], operation: ['create'], }, }, default: {}, placeholder: 'Добавить параметры конверсии', options: [ { name: 'values', displayName: 'Параметры конверсии', values: [ { displayName: 'ID клика (click_id)', name: 'click_id', type: 'string', required: true, default: '', description: 'ID клика, для которого регистрируется конверсия', }, { displayName: 'Статус', name: 'status', type: 'options', options: [ { name: 'Лид', value: 'lead', }, { name: 'Продажа', value: 'sale', }, { name: 'Отклонено', value: 'rejected', }, { name: 'Регистрация', value: 'reg', }, { name: 'Депозит', value: 'dep', }, ], default: 'lead', description: 'Статус конверсии', }, { displayName: 'Сумма дохода', name: 'revenue', type: 'number', default: 0, description: 'Сумма дохода от конверсии', }, { displayName: 'Валюта', name: 'currency', type: 'string', default: 'USD', description: 'Валюта дохода', }, { displayName: 'ID транзакции', name: 'transaction_id', type: 'string', default: '', description: 'ID транзакции (для повторных продаж/upsell)', }, { displayName: 'Комментарий', name: 'comment', type: 'string', default: '', description: 'Комментарий к конверсии', }, ], }, ], description: 'Упрощенный способ создания конверсии', }, { displayName: 'ID Домена', name: 'domainId', type: 'string', required: true, displayOptions: { show: { resource: ['domain'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID домена', }, { displayName: 'Данные Домена', name: 'domainData', type: 'json', required: true, displayOptions: { show: { resource: ['domain'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные домена в формате JSON', }, { displayName: 'ID Клика', name: 'clickId', type: 'string', required: true, displayOptions: { show: { resource: ['click'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID клика', }, { displayName: 'Данные Клика', name: 'clickData', type: 'json', required: true, displayOptions: { show: { resource: ['click'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные клика в формате JSON', }, { displayName: 'ID Фильтра', name: 'filterId', type: 'string', required: true, displayOptions: { show: { resource: ['filter'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID фильтра', }, { displayName: 'Данные Фильтра', name: 'filterData', type: 'json', required: true, displayOptions: { show: { resource: ['filter'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные фильтра в формате JSON', }, { displayName: 'ID Настроек', name: 'settingsId', type: 'string', required: true, displayOptions: { show: { resource: ['settings'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID настроек', }, { displayName: 'Данные Настроек', name: 'settingsData', type: 'json', required: true, displayOptions: { show: { resource: ['settings'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные настроек в формате JSON', }, { displayName: 'ID Лога', name: 'logId', type: 'string', required: true, displayOptions: { show: { resource: ['log'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID лога', }, { displayName: 'Данные Лога', name: 'logData', type: 'json', required: true, displayOptions: { show: { resource: ['log'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные лога в формате JSON', }, { displayName: 'ID Статистики', name: 'statsId', type: 'string', required: true, displayOptions: { show: { resource: ['stats'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID статистики', }, { displayName: 'Данные Статистики', name: 'statsData', type: 'json', required: true, displayOptions: { show: { resource: ['stats'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные статистики в формате JSON', }, { displayName: 'ID Группы', name: 'groupId', type: 'string', required: true, displayOptions: { show: { resource: ['group'], operation: ['get', 'update', 'delete'], }, }, default: '', description: 'ID группы', }, { displayName: 'Данные Группы', name: 'groupData', type: 'json', required: true, displayOptions: { show: { resource: ['group'], operation: ['create', 'update'], }, }, default: '{}', description: 'Данные группы в формате JSON', }, // Параметры для получения кликов { displayName: 'Параметры Фильтрации Кликов', name: 'clickParameters', type: 'fixedCollection', placeholder: 'Добавить параметр', default: {}, displayOptions: { show: { resource: [ 'click', ], operation: [ 'getAll', ], }, }, typeOptions: { multipleValues: false, }, description: 'Параметры для получения кликов', options: [ { name: 'range', displayName: 'Диапазон дат', values: [ { displayName: 'Начальная дата', name: 'from', type: 'string', default: '', description: 'Начальная дата в формате YYYY-MM-DD', }, { displayName: 'Конечная Дата', name: 'to', type: 'string', default: '', description: 'Конечная дата в формате YYYY-MM-DD', }, { displayName: 'Часовой пояс', name: 'timezone', type: 'string', default: '', description: 'Часовой пояс, например Europe/Moscow', }, ] }, { name: 'interval', displayName: 'Интервал', values: [ { displayName: 'Интервал', name: 'interval', type: 'options', options: [ { name: 'Сегодня', value: 'today', }, { name: 'Вчера', value: 'yesterday', }, { name: '7 дней назад', value: '7_days_ago', }, { name: 'Первый день этой недели', value: 'first_day_of_this_week', }, { name: '1 месяц назад', value: '1_month_ago', }, { name: 'Первый день этого месяца', value: 'first_day_of_this_month', }, { name: '1 год назад', value: '1_year_ago', }, { name: 'Первый день этого года', value: 'first_day_of_this_year', }, { name: 'За все время', value: 'all_time', }, ], default: '', description: 'Предустановленный интервал времени', }, ], }, { name: 'mainFilters', displayName: 'Основные фильтры', values: [ { displayName: 'ID Кампании', name: 'campaign_id', type: 'string', default: '', description: 'Фильтрация по ID кампании', }, { displayName: 'ID Потока', name: 'stream_id', type: 'string', default: '', description: 'Фильтрация по ID потока', }, { displayName: 'ID Лендинга', name: 'landing_id', type: 'string', default: '', description: 'Фильтрация по ID лендинга', }, { displayName: 'ID Оффера', name: 'offer_id', type: 'string', default: '', description: 'Фильтрация по ID оффера', }, ] }, { name: 'additionalFilters', displayName: 'Дополнительные фильтры', values: [ { displayName: 'Страна', name: 'country', type: 'string', default: '', description: 'Фильтрация по коду страны (2 буквы, например RU)', }, { displayName: 'IP', name: 'ip', type: 'string', default: '', description: 'Фильтрация по IP-адресу', }, { displayName: 'Бот', name: 'is_bot', type: 'boolean', default: false, description: 'Фильтрация по ботам', }, { displayName: 'Уникальный клик', name: 'is_unique', type: 'boolean', default: false, description: 'Фильтрация по уникальным кликам', }, { displayName: 'Конверсия', name: 'is_conversion', type: 'boolean', default: false, description: 'Фильтрация по кликам с конверсиями', }, { displayName: 'Sub ID 1', name: 'sub_id_1', type: 'string', default: '', description: 'Фильтрация по Sub ID 1', }, { displayName: 'Sub ID 2', name: 'sub_id_2', type: 'string', default: '', description: 'Фильтрация по Sub ID 2', }, { displayName: 'Sub ID 3', name: 'sub_id_3', type: 'string', default: '', description: 'Фильтрация по Sub ID 3', }, { displayName: 'Sub ID 4', name: 'sub_id_4', type: 'string', default: '', description: 'Фильтрация по Sub ID 4', }, { displayName: 'Sub ID 5', name: 'sub_id_5', type: 'string', default: '', description: 'Фильтрация по Sub ID 5', }, ] }, { name: 'pagination', displayName: 'Пагинация и сортировка', values: [ { displayName: 'Лимит', name: 'limit', type: 'number', default: 100, description: 'Максимальное количество кликов для возврата (обязательно, если не указан диапазон дат)', }, { displayName: 'Смещение', name: 'offset', type: 'number', default: 0, description: 'Смещение для пагинации', }, { displayName: 'Сортировка', name: 'sort', type: 'options', options: [ { name: 'По ID (возрастание)', value: 'id', }, { name: 'По ID (убывание)', value: '-id', }, { name: 'По времени (возрастание)', value: 'created_at', }, { name: 'По времени (убывание)', value: '-created_at', }, ], default: '-created_at', description: 'Поле и направление сортировки', }, ] } ], }, // Параметры для получения статистики { displayName: 'Параметры для Статистики', name: 'statsParameters', type: 'fixedCollection', placeholder: 'Добавить параметр', default: {}, displayOptions: { show: { resource: [ 'stats', ], operation: [ 'getAll', ], }, }, typeOptions: { multipleValues: false, }, options: [ { name: 'dateRange', displayName: 'Диапазон дат', values: [ { displayName: 'Начальная Дата', name: 'range_from', type: 'string', default: '', description: 'Начальная дата в формате YYYY-MM-DD', required: false, }, { displayName: 'Конечная Дата', name: 'range_to', type: 'string', default: '', description: 'Конечная дата в формате YYYY-MM-DD', required: false, }, ], }, { name: 'filterOptions', displayName: 'Фильтры и группировка', values: [ { displayName: 'Группировка', name: 'group', type: 'multiOptions', options: [ { name: 'По дням', value: 'day', }, { name: 'По часам', value: 'hour', }, { name: 'По ID кампании', value: 'campaign_id', }, { name: 'По ID потока', value: 'stream_id', }, { name: 'По стране', value: 'country', }, { name: 'По устройству', value: 'device_type', }, { name: 'По браузеру', value: 'browser_name', }, { name: 'По ОС', value: 'os_name', }, { name: 'По ключевому слову', value: 'keyword', }, { name: 'По Sub ID 1', value: 'sub_id_1', }, { name: 'По Sub ID 2', value: 'sub_id_2', }, { name: 'По Sub ID 3', value: 'sub_id_3', }, { name: 'По Sub ID 4', value: 'sub_id_4', }, { name: 'По Sub ID 5', value: 'sub_id_5', }, ], default: ['day'], description: 'Группировка данных статистики', }, { displayName: 'Фильтр по ID кампании', name: 'campaign', type: 'string', default: '', description: 'ID кампании для фильтрации', }, { displayName: 'Фильтр по ID потока', name: 'stream', type: 'string', default: '', description: 'ID потока для фильтрации', }, { displayName: 'Фильтр по стране', name: 'country', type: 'string', default: '', description: 'Код страны для фильтрации (2 буквы, например RU)', }, { displayName: 'Фильтр по типу устройства', name: 'device_type', type: 'options', options: [ { name: 'Мобильные', value: 'mobile', }, { name: 'Десктоп', value: 'desktop', }, { name: 'Планшеты', value: 'tablet', }, ], default: '', description: 'Тип устройства для фильтрации', }, ], }, { name: 'additionalFilters', displayName: 'Дополнительные фильтры', values: [ { displayName: 'Фильтр по Sub ID 1', name: 'sub_id_1', type: 'string', default: '', description: 'Фильтрация по Sub ID 1', }, { displayName: 'Фильтр по Sub ID 2', name: 'sub_id_2', type: 'string', default: '', description: 'Фильтрация по Sub ID 2', }, { displayName: 'Фильтр по Sub ID 3', name: 'sub_id_3', type: 'string', default: '', description: 'Фильтрация по Sub ID 3', }, { displayName: 'Фильтр по Sub ID 4', name: 'sub_id_4', type: 'string', default: '', description: 'Фильтрация по Sub ID 4', }, { displayName: 'Фильтр по Sub ID 5', name: 'sub_id_5', type: 'string', default: '', description: 'Фильтрация по Sub ID 5', }, ], }, { name: 'metrics', displayName: 'Метрики', values: [ { displayName: 'Включать ROI', name: 'roi', type: 'boolean', default: true, description: 'Включать ROI в результаты', }, { displayName: 'Включать CR', name: 'cr', type: 'boolean', default: true, description: 'Включать коэффициент конверсии (CR) в результаты', }, { displayName: 'Включать EPC', name: 'epc', type: 'boolean', default: true, description: 'Включать доход на клик (EPC) в результаты', }, { displayName: 'Включать CPC', name: 'cpc', type: 'boolean', default: true, description: 'Включать стоимость клика (CPC) в результаты', }, ], }, { name: 'interval', displayName: 'Интервал', values: [ { displayName: 'Интервал', name: 'interval', type: 'options', options: [ { name: 'Сегодня', value: 'today', }, { name: 'Вчера', value: 'yesterday', }, { name: '7 дней назад', value: '7_days_ago', }, { name: 'Первый день этой недели', value: 'first_day_of_this_week', }, { name: '1 месяц назад', value: '1_month_ago', }, { name: 'Первый день этого месяца', value: 'first_day_of_this_month', }, { name: '1 год назад', value: '1_year_ago', }, { name: 'Первый день этого года', value: 'first_day_of_this_year', }, { name: 'За все время', value: 'all_time', }, ], default: '', description: 'Предустановленный интервал времени', }, ], }, ], }, { displayName: 'Тестирование постбэка', name: 'testPostbackData', type: 'fixedCollection', typeOptions: { multipleValues: false, }, displayOptions: { show: { resource: ['postback'], operation: ['test'], }, }, default: {}, placeholder: 'Добавить тестовые данные', options: [ { name: 'testData', displayName: 'Тестовые данные', values: [ { displayName: 'ID клика (SubID)', name: 'click_id', type: 'string', required: true, default: '', description: 'ID клика для тестирования постбэка', }, { displayName: 'Статус', name: 'status', type: 'options', options: [ { name: 'Лид', value: 'lead', }, { name: 'Продажа', value: 'sale', }, { name: 'Отклонено', value: 'rejected', }, { name: 'Регистрация', value: 'reg', }, { name: 'Депозит', value: 'dep', }, ], default: 'lead', description: 'Статус конверсии', }, { displayName: 'Сумма выплаты', name: 'payout', type: 'number', default: 10, description: 'Сумма выплаты за конверсию', }, { displayName: 'Стоимость', name: 'cost', type: 'number', default: 0, description: 'Стоимость за конверсию (для CPA и RevShare)', }, { displayName: 'Валюта', name: 'currency', type: 'string', default: 'USD', description: 'Валюта выплаты', }, { displayName: 'ID транзакции', name: 'transaction_id', type: 'string', default: '', description: 'ID транзакции (для повторных продаж/upsell)', }, { displayName: 'Sub ID 1', name: 'sub_id_1', type: 'string', default: '', description: 'Значение Sub ID 1 для обновления параметров клика', }, ], }, ], description: 'Данные для тестирования постбэка', }, { displayName: 'Настройка HTTP заголовков', name: 'postbackConfigureHeaders', type: 'boolean', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], postbackAdvanced: [true], }, }, default: false, description: 'Настройка HTTP заголовков для отправки постбека', }, { displayName: 'HTTP заголовки', name: 'postbackHeaders', type: 'fixedCollection', typeOptions: { multipleValues: true, }, displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], postbackAdvanced: [true], postbackConfigureHeaders: [true], }, }, default: {}, placeholder: 'Добавить HTTP заголовок', options: [ { name: 'header', displayName: 'Заголовок', values: [ { displayName: 'Имя', name: 'name', type: 'string', default: '', description: 'Имя HTTP заголовка', placeholder: 'Content-Type', }, { displayName: 'Значение', name: 'value', type: 'string', default: '', description: 'Значение HTTP заголовка', placeholder: 'application/json', }, ], }, ], description: 'HTTP заголовки для отправки с постбеком', }, { displayName: 'Параметры постбека', name: 'postbackParameters', type: 'fixedCollection', typeOptions: { multipleValues: true, }, displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], postbackAdvanced: [true], }, }, default: {}, placeholder: 'Добавить параметр', options: [ { name: 'parameter', displayName: 'Параметр', values: [ { displayName: 'Имя', name: 'name', type: 'string', default: '', description: 'Имя параметра', placeholder: 'subid, status, payout и т.д.', }, { displayName: 'Значение', name: 'value', type: 'string', default: '', description: 'Значение параметра или макрос {sub_id_1}, {status}, и т.д.', placeholder: '{sub_id_1}', }, ], }, ], description: 'Дополнительные параметры для постбека', }, { displayName: 'Статусы для отслеживания регистраций', name: 'regStatus', type: 'string', displayOptions: { show: { resource: ['postback'], operation: ['create', 'update'], postbackAdvanced: [true], }, }, default: 'reg,registration', description: 'Статусы для регистраций, перечисленные через запятую. Для Keitaro 10.3+.', }, { displayName: 'Статусы для отслеживания депозитов', name: 'depStatus', type: 'string', displayOptions: { show: { resou