← Назад
import 'dotenv/config'; const ACCESS_KEY = process.env.BEMOB_ACCESS_KEY; const SECRET_KEY = process.env.BEMOB_SECRET_KEY; const BASE = process.env.BEMOB_API_URL || 'https://api.bemob.com'; if (!ACCESS_KEY || !SECRET_KEY) { console.error('❌ BEMOB_ACCESS_KEY / BEMOB_SECRET_KEY not set in .env'); process.exit(1); } const headers = { 'X-Access-Key': ACCESS_KEY, 'X-Secret-Key': SECRET_KEY, 'Content-Type': 'application/json', }; // ─── Core API ────────────────────────────────────────── const api = async (method, path, body = null) => { const opts = { method, headers }; if (body) opts.body = JSON.stringify(body); const res = await fetch(`${BASE}${path}`, opts); const data = await res.json(); if (!data.success) { throw new Error(`BeMob API error: ${JSON.stringify(data.errors || data.message)}`); } return data.payload; }; const get = (path) => api('GET', path); const post = (path, body) => api('POST', path, body); const put = (path, body) => api('PUT', path, body); const del = (path) => api('DELETE', path); // ─── Entities ────────────────────────────────────────── const user = () => get('/v1/user'); const trafficSources = () => get('/v1/traffic-sources'); const affiliateNetworks = () => get('/v1/affiliate-networks'); const campaigns = () => get('/v1/campaigns'); const offers = () => get('/v1/offers'); const landings = () => get('/v1/landings'); const flows = () => get('/v1/flows'); // ─── Create entities ─────────────────────────────────── const createOffer = (data) => post('/v1/offers', data); const createLanding = (data) => post('/v1/landings', data); const createCampaign = (data) => post('/v1/campaigns', data); const createFlow = (data) => post('/v1/flows', data); // ─── Update entities ─────────────────────────────────── const updateCampaign = (id, data) => put(`/v1/campaigns/${id}`, data); const updateOffer = (id, data) => put(`/v1/offers/${id}`, data); const updateLanding = (id, data) => put(`/v1/landings/${id}`, data); // ─── Reports ─────────────────────────────────────────── const report = (params = {}) => { const qs = new URLSearchParams(params).toString(); return get(`/v1/reports${qs ? '?' + qs : ''}`); }; // ─── CLI ─────────────────────────────────────────────── const [cmd, ...args] = process.argv.slice(2); const fmt = (items) => { if (!items || (Array.isArray(items) && items.length === 0)) { console.log(' (пусто)'); return; } if (Array.isArray(items)) { items.forEach((item) => { console.log(` β€’ ${item.name || item.id} [${item.status || ''}] id:${item.id}`); if (item.campaignUrl) console.log(` URL: ${item.campaignUrl}`); if (item.url) console.log(` URL: ${item.url}`); if (item.destinationUrl) console.log(` Dest: ${item.destinationUrl}`); }); } else { console.log(JSON.stringify(items, null, 2)); } }; const commands = { async user() { console.log('\nπŸ‘€ BeMob User\n'); const u = await user(); console.log(` Name: ${u.firstName} ${u.lastName}`); console.log(` Email: ${u.email}`); console.log(` Plan: ${u.subscriptionPlan}`); console.log(` Tracking: ${u.trackingDomainCNAME}`); console.log(` Subdomain: ${u.subdomain}`); }, async campaigns() { console.log('\nπŸ“’ Campaigns\n'); fmt(await campaigns()); }, async sources() { console.log('\nπŸ”— Traffic Sources\n'); fmt(await trafficSources()); }, async networks() { console.log('\n🏒 Affiliate Networks\n'); fmt(await affiliateNetworks()); }, async offers() { console.log('\n🎯 Offers\n'); fmt(await offers()); }, async landings() { console.log('\nπŸ“„ Landings\n'); fmt(await landings()); }, async flows() { console.log('\nπŸ”€ Flows\n'); fmt(await flows()); }, async all() { await commands.user(); await commands.sources(); await commands.networks(); await commands.offers(); await commands.landings(); await commands.campaigns(); }, async setup() { console.log('\nπŸ”§ Setting up BeMob for arbitrage...\n'); // IDs from existing setup const POPADS_ID = '926837ec-ba08-4b90-af96-6007057dcd2b'; const MOBIDEA_ID = 'a644ec65-dda3-4363-94c0-d21cdd936270'; const WORKSPACE_ID = '1e183b44-fe18-4ef2-ad08-44af43a4b172'; // SmartLink URLs const CPI_URL = process.env.MOBIDEA_CPI; const MAINSTREAM_URL = process.env.MOBIDEA_MAINSTREAM; // Step 1: Create Offers console.log('1️⃣ Creating offers...'); const offerCPI = await createOffer({ name: 'Mobidea CPI SmartLink', url: CPI_URL, affiliateNetworkId: MOBIDEA_ID, workspaceId: WORKSPACE_ID, status: 'active', payoutType: 'auto', enableDailyCap: false, currencyId: 'USD', }); console.log(` βœ… CPI Offer: ${offerCPI.id}`); const offerMainstream = await createOffer({ name: 'Mobidea Mainstream SmartLink', url: MAINSTREAM_URL, affiliateNetworkId: MOBIDEA_ID, workspaceId: WORKSPACE_ID, status: 'active', payoutType: 'auto', enableDailyCap: false, currencyId: 'USD', }); console.log(` βœ… Mainstream Offer: ${offerMainstream.id}`); // Step 2: Create Landing Pages console.log('\n2️⃣ Creating landing pages...'); const prelanders = [ { name: 'Opera Security Scan', sub: 'scan' }, { name: 'Opera Speed Test', sub: 'speed' }, { name: 'Opera Top 3 Review', sub: 'review' }, { name: 'AdBlock Scanner', sub: 'shield' }, { name: 'AdBlock Before/After', sub: 'clean' }, { name: 'AdBlock YouTube', sub: 'block' }, { name: 'Wheel Spin', sub: 'win' }, ]; const landingIds = {}; const cpiOfferId = offerCPI.id; const mainstreamOfferId = offerMainstream.id; for (const lp of prelanders) { const offerId = lp.sub === 'win' ? mainstreamOfferId : cpiOfferId; const landing = await createLanding({ name: lp.name, url: `https://${lp.sub}.clkway.online`, workspaceId: WORKSPACE_ID, status: 'active', offers: [offerId], }); landingIds[lp.sub] = landing.id; console.log(` βœ… ${lp.name}: ${landing.id}`); } // Step 3: Create Campaigns with flows (landing β†’ offer) console.log('\n3️⃣ Creating campaigns...'); // CPI campaigns (Opera + AdBlock prelanders) const cpiLandings = ['scan', 'speed', 'review', 'shield', 'clean', 'block']; for (const sub of cpiLandings) { const lp = prelanders.find((p) => p.sub === sub); const campaign = await createCampaign({ name: `CPI - ${lp.name} - Pop`, trafficSourceId: POPADS_ID, workspaceId: WORKSPACE_ID, status: 'active', costModel: 'auto', destinationType: 'flow-built-in', flowInline: { rules: [{ name: 'Default', default: true, conditions: {}, status: 'active', paths: [{ name: 'Path 1', weight: 100, status: 'active', directLinking: false, landings: [{ id: landingIds[sub], weight: 100 }], offers: [{ id: offerCPI.id, weight: 100 }], }], }], }, }); console.log(` βœ… ${campaign.name}`); console.log(` URL: ${campaign.campaignUrl}`); } // Mainstream campaign (Wheel) const wheelCampaign = await createCampaign({ name: 'Mainstream - Wheel Spin - Pop', trafficSourceId: POPADS_ID, workspaceId: WORKSPACE_ID, status: 'active', costModel: 'auto', destinationType: 'flow-built-in', flowInline: { rules: [{ name: 'Default', default: true, conditions: {}, status: 'active', paths: [{ name: 'Path 1', weight: 100, status: 'active', directLinking: false, landings: [{ id: landingIds.win, weight: 100 }], offers: [{ id: offerMainstream.id, weight: 100 }], }], }], }, }); console.log(` βœ… ${wheelCampaign.name}`); console.log(` URL: ${wheelCampaign.campaignUrl}`); console.log('\nπŸŽ‰ Setup complete! Use campaign URLs in PopAds.\n'); }, async help() { console.log(` πŸ”§ BeMob CLI ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€: node bemob.js user β€” Π˜Π½Ρ„ΠΎ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π° node bemob.js campaigns β€” Бписок ΠΊΠ°ΠΌΠΏΠ°Π½ΠΈΠΉ node bemob.js sources β€” Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊΠΈ Ρ‚Ρ€Π°Ρ„ΠΈΠΊΠ° node bemob.js networks β€” ΠŸΠ°Ρ€Ρ‚Π½Ρ‘Ρ€ΡΠΊΠΈΠ΅ сСти node bemob.js offers β€” ΠžΡ„Ρ„Π΅Ρ€Ρ‹ node bemob.js landings β€” Π›Π΅Π½Π΄ΠΈΠ½Π³ΠΈ node bemob.js flows β€” ΠŸΠΎΡ‚ΠΎΠΊΠΈ node bemob.js all β€” Всё сразу Настройка: node bemob.js setup β€” Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΎΡ„Ρ„Π΅Ρ€Ρ‹ + Π»Π΅Π½Π΄ΠΈΠ½Π³ΠΈ + ΠΊΠ°ΠΌΠΏΠ°Π½ΠΈΠΈ `); }, }; const run = commands[cmd] || commands.help; run().catch((err) => { console.error(`❌ ${err.message}`); process.exit(1); }); export { api, get, post, put, del, user, campaigns, offers, landings, trafficSources, affiliateNetworks, createOffer, createLanding, createCampaign };