Skip to content

Meta Ads

Your agents build Facebook and Instagram campaigns on your Meta ad account, move budget to the winning ad, and stop spend by your rule.

Connect
Sign in once, 4 grants
Runs through
Your account
First run
Read the ads your rivals have run longest, about 0.2¢
Campaign.create
You, to your agent

Build a $400 Meta message test with two headlines for property managers, and show me what Meta would accept.

curl -X POST "https://api.sb/leaseline.app/campaigns/create?mode=try" \
  -H "Authorization: Bearer $SB_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"venue":"facebook","objective":"traffic","budget":{"amount":400,"currency":"USD","per":"test"},"ads":["ads/rent-spreadsheet-a","ads/rent-spreadsheet-b"],"stopRule":"pause the losing headline at 7,700 impressions each"}'
npx startup-builder do Campaign.create --try --data '{"venue":"facebook","objective":"traffic","budget":{"amount":400,"currency":"USD","per":"test"},"ads":["ads/rent-spreadsheet-a","ads/rent-spreadsheet-b"],"stopRule":"pause the losing headline at 7,700 impressions each"}'
{
  "name": "do",
  "arguments": {
    "mode": "try",
    "code": "return await $.Campaign.create({ venue: 'facebook', objective: 'traffic', budget: { amount: 400, currency: 'USD', per: 'test' }, ads: ['ads/rent-spreadsheet-a', 'ads/rent-spreadsheet-b'], stopRule: 'pause the losing headline at 7,700 impressions each' })"
  }
}
import { $ } from 'startup-builder'

const result = await $.try.Campaign.create({ venue: 'facebook', objective: 'traffic', budget: { amount: 400, currency: 'USD', per: 'test' }, ads: ['ads/rent-spreadsheet-a', 'ads/rent-spreadsheet-b'], stopRule: 'pause the losing headline at 7,700 impressions each' })
Response
{
  "$type": "Campaign",
  "mode": "try",
  "stored": false,
  "venue": "facebook",
  "placements": [
    "facebook",
    "instagram"
  ],
  "objective": "OUTCOME_TRAFFIC",
  "optimizeFor": "landing-page views",
  "budget": {
    "amount": 400,
    "currency": "USD"
  },
  "validation": {
    "validateOnly": true,
    "success": true,
    "rejected": []
  },
  "estimate": {
    "impressionsEach": 12000,
    "readAt": 7700
  },
  "stopRule": "pause the losing headline at 7,700 impressions each"
}
Try mode reads, stores nothing and spends nothingAPI referenceIts Nouns

Connect once

  1. Call Integration.connect with system: 'ads' and venue: 'facebook', then open the connectUrl it returns and sign in as yourself with Meta.
  2. Pick the Business, the ad account, the page the ads run as, and the pixel on your site.
  3. Set the spend on your standing approval with Mandate.authorize: the most your agents may spend a day and in all; Meta bills your ad account, never the platform.
GrantWhat it unlocksScope
Build and change adsCampaigns, ad sets, creatives and ads, and pausing or rebudgeting themads_management
Read resultsSpend, reach, clicks and results by campaign, ad set, ad, day and placementads_read
Business assetsThe ad account, page and pixel your Business holdsbusiness_management
Lead-ad leadsEach lead-form entry the moment it is submittedleads_retrieval
ToDo this
PauseIntegration.pause stops every call through Meta at once and keeps the token; Integration.resume picks up from the same cursor.
ReconnectIntegration.reconnect returns a fresh connectUrl that lasts one hour, and keeps the Integration's id and cursor, so nothing imports twice.
DisconnectIntegration.revoke revokes the token with Meta; every record it brought in stays in your records.

What your agents do

AskVerbRuns throughPrice
Turn my approved list into a custom audience and a 1% lookalike.Audience.createYour accountFree
Build a $400 message test: one campaign, one ad set, two headlines.Campaign.createYour accountFree
Add a third ad with the winning headline and the new image.Ad.createYour accountFree
Move the budget to the winner and pause the other.Campaign.updateYour accountFree
Show me spend, clicks and cost per signup by ad for the last 7 days.Metric.queryYour accountFree
Qualify each lead-ad entry as it arrives.Lead.qualifyYour accountFree

Calls on your own account are free; Meta bills your spend directly.

Reading this site’s public data needs no account: Ad.find is a Data call (the three ways a call runs).

What it holds

NounThe account’s objectWhenWhich side leads
CampaigncampaignYour agent builds itYour records
Adadset, ad and adcreativeYour agent builds it; Meta’s review sets its statusYour records
AudiencecustomaudienceYour agent matches a listYour records
Leadleadgen entrySomeone submits a lead formThe account
Entryinsights: spendEach day’s spend settlesThe account

Events and webhooks

DirectionEvent
EmitsCampaign.created, Campaign.updated, Ad.created, Audience.created, Lead.created, Entry.posted
Hears leadgenBecomes Lead.created
Hears ad review statusBecomes Ad.updated

Any Event can wake a Workflow, and a Watch delivers it to your endpoint, signed (Events and webhooks).

Limits

WhatLimitCall
Minimum daily budgetMeta sets it per ad account, currency and what the ad set pays for; the agent reads it from your ad account before it builds, and a budget under it refuses with venue-rejectedCampaign.create
Ad reviewMeta reviews every new ad before it runs; a disapproval comes back as venue-rejected with Meta’s reasonAd.create
SpendYour standing approval holds the daily and total cap; a change past it waits with over-mandateCampaign.update
One ad setA test under $1,000 runs in one ad set, never split, so every result feeds the same learningCampaign.create

Start here

MoveThe rule
StructureOne campaign on the traffic objective, one ad set with a broad audience optimizing for landing-page views, and two ads that differ in one phrase of the headline.
Budget$300 to $500 for the message test. Optimize for signups only when a week’s budget reaches 50 times your cost per signup: at $25 a signup, $1,250 a week for one ad set.
CreativeA 4:5 feed image at 1440 × 1800, primary text of 50 to 150 characters and a headline under 27; both ads share the image and differ in one headline phrase.
Kill ruleRead at about 7,700 impressions a headline: keep the one ahead by 50% or more and pause the other. With no winner at $500, stop and rewrite the angle before you touch the image.
BenchmarkSource
An ad set leaves learning at about 50 optimization events in 7 daysPractitioner reports, consistent across sources
Two headlines at 1% CTR need about 7,700 impressions each to show a 50% liftOur calculation: 80% power, 5% two-sided
$400 at about $16 per 1,000 impressions buys 12,000 impressions for each of 2 headlinesOur planning number

Field map

Our fieldMeta Ads’s fieldNotesCalls
Campaign.objectivecampaign.objectiveleads is OUTCOME_LEADS, traffic OUTCOME_TRAFFIC, conversions OUTCOME_SALESCampaign.create, Campaign.update, Ad.create
Campaign.budgetadset.daily_budget or adset.lifetime_budgetIn the account currency’s smallest unit: $40.00 is 4000Campaign.create, Campaign.update, Ad.create
Campaign.startsAtadset.start_timeNone.Campaign.create
Campaign.endsAtadset.end_timeNone.Campaign.create
Campaign.statecampaign.statuslive is ACTIVE, paused is PAUSEDCampaign.update
Ad.bodyobject_story_spec.link_data.messageThe primary textAd.create
Ad.headlineobject_story_spec.link_data.nameNone.Ad.create
Ad.landingUrlobject_story_spec.link_data.linkNone.Ad.create
Audience.querycustomaudience (subtype CUSTOM)Emails are hashed before they leave your recordsAudience.create
Audience.lookalikelookalike_spec.ratio1 is 0.01Audience.create
Lead.interestleadgen.field_dataNone.Lead.qualify

What try does here

Sends the whole build with Meta’s validate_only execution option: Meta runs every check and creates nothing, and the response names any field it would reject.

How long a connection lasts

A connection lasts about 60 days, the life of Meta’s long-lived sign-in; you sign in with Meta again to start the next 60.

The platform asks you to reconnect 7 days before it runs out; until you do, a call that needs it refuses with needs-reauth.

Formats

SiteFormatSizeLimits
FacebookFeed image ad1440 × 1800, 4:5Primary text 50 to 150 characters; headline 27; up to 30 megabytes
InstagramFeed image320 to 1,440 pixels wide, 4:5 to 1.91:1JPEG only, up to 8 megabytes; caption 2,200 characters, 30 hashtags, 20 mentions
InstagramCarouselNone.Up to 20 images or videos, cropped to the first item’s ratio; counts as one post
InstagramReel9:16MOV or MP4, 3 seconds to 15 minutes, up to 300 megabytes, 23 to 60 frames a second
InstagramStory9:16Image up to 8 megabytes; video 3 to 60 seconds, up to 100 megabytes

Plays and strategies

Used by

Reference

6 calls, each with its path and price
CallPathPrice
Audience.createPOST /audiences/createFree
Campaign.createPOST /campaigns/createFree
Ad.createPOST /ads/createFree
Campaign.updatePOST /campaigns/updateFree
Metric.queryPOST /metrics/queryFree
Lead.qualifyPOST /leads/qualifyFree

Contents