← Back
β˜†
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 };

πŸ“œ Git History

71dd65fchore: initial commit β€” version control setup5 weeks ago
Show last diff
Loading...