Skip to main content
Glama

Facebook Ads Management Control Panel

by codprocess
adSets.js15.3 kB
/** * Ad Sets routes * Handles operations related to Facebook ad sets */ const express = require('express'); const router = express.Router(); const { protect, checkFacebookToken } = require('../middleware/auth'); const { validate, schemas } = require('../middleware/validator'); const { sendSuccess, sendError, sendPaginated } = require('../utils/responseFormatter'); const { NotFoundError, ValidationError } = require('../utils/errorTypes'); const AdSet = require('../models/adSet'); const Campaign = require('../models/campaign'); const facebookApiService = require('../services/facebookApiService'); const analyticsService = require('../services/analyticsService'); const logger = require('../utils/logger'); /** * @route GET /api/ad-sets * @desc Get all ad sets for the current user * @access Private */ router.get('/', protect, async (req, res, next) => { try { // Get pagination parameters const page = parseInt(req.query.page) || 1; const limit = parseInt(req.query.limit) || 20; const skip = (page - 1) * limit; // Build query const query = { userId: req.user._id }; // Filter by campaign if provided if (req.query.campaignId) { query.campaignId = req.query.campaignId; } // Filter by status if provided if (req.query.status) { query.status = req.query.status; } // Get ad sets from database const adSets = await AdSet.find(query) .sort({ createdAt: -1 }) .skip(skip) .limit(limit); // Get total count const total = await AdSet.countDocuments(query); return sendPaginated(res, adSets, page, limit, total, 'Ad sets retrieved successfully'); } catch (error) { logger.error(`Error retrieving ad sets: ${error.message}`); return next(error); } }); /** * @route GET /api/ad-sets/sync * @desc Sync ad sets from Facebook * @access Private */ router.get('/sync', protect, checkFacebookToken, async (req, res, next) => { try { // Get campaign ID from query params const { campaignId } = req.query; if (!campaignId) { return next(new ValidationError('Campaign ID is required')); } // Check if campaign exists const campaign = await Campaign.findOne({ campaignId, userId: req.user._id }); if (!campaign) { return next(new NotFoundError('Campaign not found')); } // Create Facebook API service const fbApi = await facebookApiService.createForUser(req.user); // Get ad sets from Facebook const fbAdSets = await fbApi.getAdSets(campaignId); // Process and save ad sets const savedAdSets = []; for (const fbAdSet of fbAdSets) { // Find existing ad set or create new one let adSet = await AdSet.findOne({ adSetId: fbAdSet.id, userId: req.user._id }); if (!adSet) { adSet = new AdSet({ adSetId: fbAdSet.id, campaignId, userId: req.user._id }); } // Update ad set details adSet.name = fbAdSet.name; adSet.status = fbAdSet.status; adSet.targeting = fbAdSet.targeting || {}; adSet.optimization = fbAdSet.optimization_goal; adSet.bidStrategy = fbAdSet.bid_strategy; adSet.bidAmount = fbAdSet.bid_amount; adSet.budget = fbAdSet.daily_budget || fbAdSet.lifetime_budget; adSet.budgetType = fbAdSet.daily_budget ? 'DAILY' : 'LIFETIME'; adSet.startTime = fbAdSet.start_time ? new Date(fbAdSet.start_time) : null; adSet.endTime = fbAdSet.end_time ? new Date(fbAdSet.end_time) : null; adSet.lastSyncedAt = new Date(); // Save ad set await adSet.save(); savedAdSets.push(adSet); } return sendSuccess(res, savedAdSets, 'Ad sets synced successfully'); } catch (error) { logger.error(`Error syncing ad sets: ${error.message}`); return next(error); } }); /** * @route POST /api/ad-sets * @desc Create a new ad set * @access Private */ router.post('/', protect, checkFacebookToken, validate(schemas.adSet.create), async (req, res, next) => { try { // Check if campaign exists const campaign = await Campaign.findOne({ campaignId: req.body.campaignId, userId: req.user._id }); if (!campaign) { return next(new NotFoundError('Campaign not found')); } // Create Facebook API service const fbApi = await facebookApiService.createForUser(req.user); // Prepare ad set data for Facebook const adSetData = { name: req.body.name, campaign_id: req.body.campaignId, status: req.body.status || 'PAUSED', targeting: req.body.targeting, optimization_goal: req.body.optimization, bid_strategy: req.body.bidStrategy, bid_amount: req.body.bidAmount, start_time: req.body.startTime, end_time: req.body.endTime }; // Set budget based on budget type if (req.body.budgetType === 'DAILY' || !req.body.budgetType) { adSetData.daily_budget = req.body.budget; } else { adSetData.lifetime_budget = req.body.budget; } // Create ad set on Facebook const fbResponse = await fbApi.createAdSet(campaign.adAccountId, adSetData); // Create ad set in database const adSet = new AdSet({ adSetId: fbResponse.id, name: req.body.name, campaignId: req.body.campaignId, userId: req.user._id, status: req.body.status || 'PAUSED', targeting: req.body.targeting, optimization: req.body.optimization, bidStrategy: req.body.bidStrategy, bidAmount: req.body.bidAmount, budget: req.body.budget, budgetType: req.body.budgetType || 'DAILY', startTime: req.body.startTime, endTime: req.body.endTime, lastSyncedAt: new Date() }); // Save ad set await adSet.save(); return sendSuccess(res, adSet, 'Ad set created successfully', 201); } catch (error) { logger.error(`Error creating ad set: ${error.message}`); return next(error); } }); /** * @route GET /api/ad-sets/:id * @desc Get ad set by ID * @access Private */ router.get('/:id', protect, validate(schemas.idParam, 'params'), async (req, res, next) => { try { // Get ad set from database const adSet = await AdSet.findOne({ adSetId: req.params.id, userId: req.user._id }); if (!adSet) { return next(new NotFoundError('Ad set not found')); } return sendSuccess(res, adSet, 'Ad set retrieved successfully'); } catch (error) { logger.error(`Error retrieving ad set: ${error.message}`); return next(error); } }); /** * @route PUT /api/ad-sets/:id * @desc Update ad set * @access Private */ router.put('/:id', protect, checkFacebookToken, validate(schemas.idParam, 'params'), validate(schemas.adSet.update), async (req, res, next) => { try { // Get ad set from database const adSet = await AdSet.findOne({ adSetId: req.params.id, userId: req.user._id }); if (!adSet) { return next(new NotFoundError('Ad set not found')); } // Create Facebook API service const fbApi = await facebookApiService.createForUser(req.user); // Prepare ad set data for Facebook const adSetData = {}; if (req.body.name) adSetData.name = req.body.name; if (req.body.status) adSetData.status = req.body.status; if (req.body.targeting) adSetData.targeting = req.body.targeting; if (req.body.optimization) adSetData.optimization_goal = req.body.optimization; if (req.body.bidStrategy) adSetData.bid_strategy = req.body.bidStrategy; if (req.body.bidAmount) adSetData.bid_amount = req.body.bidAmount; if (req.body.startTime) adSetData.start_time = req.body.startTime; if (req.body.endTime) adSetData.end_time = req.body.endTime; // Set budget based on budget type if (req.body.budget) { if (req.body.budgetType === 'DAILY' || (!req.body.budgetType && adSet.budgetType === 'DAILY')) { adSetData.daily_budget = req.body.budget; } else { adSetData.lifetime_budget = req.body.budget; } } // Update ad set on Facebook await fbApi.updateAdSet(req.params.id, adSetData); // Update ad set in database if (req.body.name) adSet.name = req.body.name; if (req.body.status) adSet.status = req.body.status; if (req.body.targeting) adSet.targeting = req.body.targeting; if (req.body.optimization) adSet.optimization = req.body.optimization; if (req.body.bidStrategy) adSet.bidStrategy = req.body.bidStrategy; if (req.body.bidAmount) adSet.bidAmount = req.body.bidAmount; if (req.body.budget) adSet.budget = req.body.budget; if (req.body.budgetType) adSet.budgetType = req.body.budgetType; if (req.body.startTime) adSet.startTime = req.body.startTime; if (req.body.endTime) adSet.endTime = req.body.endTime; adSet.lastSyncedAt = new Date(); // Save ad set await adSet.save(); return sendSuccess(res, adSet, 'Ad set updated successfully'); } catch (error) { logger.error(`Error updating ad set: ${error.message}`); return next(error); } }); /** * @route DELETE /api/ad-sets/:id * @desc Delete ad set * @access Private */ router.delete('/:id', protect, checkFacebookToken, validate(schemas.idParam, 'params'), async (req, res, next) => { try { // Get ad set from database const adSet = await AdSet.findOne({ adSetId: req.params.id, userId: req.user._id }); if (!adSet) { return next(new NotFoundError('Ad set not found')); } // Create Facebook API service const fbApi = await facebookApiService.createForUser(req.user); // Delete ad set on Facebook (actually sets status to DELETED) await fbApi.updateAdSet(req.params.id, { status: 'DELETED' }); // Update ad set status in database adSet.status = 'DELETED'; await adSet.save(); return sendSuccess(res, { id: req.params.id }, 'Ad set deleted successfully'); } catch (error) { logger.error(`Error deleting ad set: ${error.message}`); return next(error); } }); /** * @route GET /api/ad-sets/:id/insights * @desc Get insights for an ad set * @access Private */ router.get('/:id/insights', protect, checkFacebookToken, validate(schemas.idParam, 'params'), async (req, res, next) => { try { // Get ad set from database const adSet = await AdSet.findOne({ adSetId: req.params.id, userId: req.user._id }); if (!adSet) { return next(new NotFoundError('Ad set not found')); } // Create Facebook API service const fbApi = await facebookApiService.createForUser(req.user); // Get time range from query params const timeRange = req.query.timeRange || 'last_30_days'; // Get insights from Facebook const insights = await fbApi.getInsights(req.params.id, timeRange, [], { level: 'adset' }); return sendSuccess(res, insights, 'Ad set insights retrieved successfully'); } catch (error) { logger.error(`Error retrieving ad set insights: ${error.message}`); return next(error); } }); /** * @route GET /api/ad-sets/:id/ads * @desc Get ads for an ad set * @access Private */ router.get('/:id/ads', protect, checkFacebookToken, validate(schemas.idParam, 'params'), async (req, res, next) => { try { // Get ad set from database const adSet = await AdSet.findOne({ adSetId: req.params.id, userId: req.user._id }); if (!adSet) { return next(new NotFoundError('Ad set not found')); } // Create Facebook API service const fbApi = await facebookApiService.createForUser(req.user); // Get ads from Facebook const ads = await fbApi.getAds(req.params.id); return sendSuccess(res, ads, 'Ad set ads retrieved successfully'); } catch (error) { logger.error(`Error retrieving ad set ads: ${error.message}`); return next(error); } }); /** * @route GET /api/ad-sets/:id/analytics * @desc Get analytics for an ad set * @access Private */ router.get('/:id/analytics', protect, validate(schemas.idParam, 'params'), validate(schemas.analytics.query, 'query'), async (req, res, next) => { try { // Get ad set from database const adSet = await AdSet.findOne({ adSetId: req.params.id, userId: req.user._id }); if (!adSet) { return next(new NotFoundError('Ad set not found')); } // Create analytics service const analytics = analyticsService.createForUser(req.user); // Get start and end dates from query params const startDate = new Date(req.query.startDate); const endDate = new Date(req.query.endDate); // Get analytics data const analyticsData = await analytics.getAdSetAnalytics(req.params.id, startDate, endDate); return sendSuccess(res, analyticsData, 'Ad set analytics retrieved successfully'); } catch (error) { logger.error(`Error retrieving ad set analytics: ${error.message}`); return next(error); } }); /** * @route POST /api/ad-sets/:id/fetch-analytics * @desc Fetch and store analytics for an ad set * @access Private */ router.post('/:id/fetch-analytics', protect, checkFacebookToken, validate(schemas.idParam, 'params'), async (req, res, next) => { try { // Get ad set from database const adSet = await AdSet.findOne({ adSetId: req.params.id, userId: req.user._id }); if (!adSet) { return next(new NotFoundError('Ad set not found')); } // Create analytics service const analytics = analyticsService.createForUser(req.user); // Get time range from query params const timeRange = req.query.timeRange || 'last_30_days'; // Fetch and store analytics data const analyticsData = await analytics.fetchAdSetAnalytics(req.params.id, timeRange); return sendSuccess(res, analyticsData, 'Ad set analytics fetched successfully'); } catch (error) { logger.error(`Error fetching ad set analytics: ${error.message}`); return next(error); } }); /** * @route GET /api/ad-sets/:id/targeting-recommendations * @desc Get targeting recommendations for an ad set * @access Private */ router.get('/:id/targeting-recommendations', protect, validate(schemas.idParam, 'params'), async (req, res, next) => { try { // Get ad set from database const adSet = await AdSet.findOne({ adSetId: req.params.id, userId: req.user._id }); if (!adSet) { return next(new NotFoundError('Ad set not found')); } // Create recommendation service const recommendationService = require('../services/recommendationService').createForUser(req.user); // Get targeting recommendations const recommendations = await recommendationService.getTargetingRecommendations(req.params.id); return sendSuccess(res, recommendations, 'Ad set targeting recommendations retrieved successfully'); } catch (error) { logger.error(`Error retrieving ad set targeting recommendations: ${error.message}`); return next(error); } }); module.exports = router;

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/codprocess/facebook-ads-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server