Ads
Facebook advertising, on the same connection as Pages. These are platform-specific routes rather than a normalized surface: campaign structure has no equivalent on the other providers Adeli covers.
Every endpoint needs a Facebook connection whose authorization includes the ads
permissions. A connection made before those were requested keeps working for
Pages and answers 403 ads_permission_required here, with the missing scopes in
error.details.missingScopes; the fix is another authorization, not a repair.
Campaign and metric reads are live. Adeli stores no campaign structure and no metrics, so every figure is as fresh as that response. The one exception is the list of ad accounts, which is reused for up to 15 minutes.
When Meta throttles a request, the response is 429 rate_limited with a
Retry-After header, error.details.retryAfterSeconds (Meta's own estimate
when it gives one, otherwise a minute) and error.details.limit: app when the
app's hourly call budget for this connection is spent, ad_account when that
ad account's own budget is.
When Meta refuses a request and explains why, the response is 422 provider_rejected with Meta's explanation in error.message — for example
that a Business portfolio has reached its limit of ad accounts.
GET/api/v1/ads/accountsList ad accounts
Every ad account the connection can reach, both directly assigned and owned by
a Business portfolio the authorizing person administers. businessId is null
for a directly-assigned account.
The list is reused for up to 15 minutes; fetchedAt is when the oldest part
of it was read from Meta. Pass refresh=true after granting access to a new ad account to see it
immediately. Other endpoints re-list on their own when given an ad account id
the stored list does not contain.
Query parameters
accountIduuid- A connected Facebook account. Defaults to the profile's.
profileIduuid- Defaults to your key's profile.
refreshboolean- true to ask Meta again instead of using the stored list.
POST/api/v1/ads/accountsCreate an ad account
Creates an ad account in a Business portfolio the authorizing person
administers. Meta has no API for personal ad accounts. The currency and time
zone cannot be changed afterwards, and a portfolio may only hold a limited
number of ad accounts — commonly one until it has spend history — which Meta
reports as 422 provider_rejected.
An Idempotency-Key header is required, since a retry would be a second ad
account: the same key replays 200 with the same account, 409 ad_account_create_failed if it failed, or 409 ad_account_create_in_progress.
A new account is 201, and the account list is refreshed to include it.
Body
businessIdstringRequired- A portfolio from GET `/api/v1/ads/businesses`.
namestringRequired- Up to 100 characters.
timezonestringRequired- An IANA zone Adeli maps to Meta's time zone id, such as America/New_York or Europe/London.
currencystring- ISO 4217. Defaults to USD.
GET/api/v1/ads/businessesList Business portfolios
The portfolios the authorizing person administers — the ones an ad account can be created in.
GET/api/v1/ads/accounts/{adAccountId}Ad account details
The account as listed, plus details: accountStatus, disableReason,
amountSpent and spendCap in whole currency units (spendCap is null when
there is none), and hasPaymentMethod — null when Meta withholds it, which it
does unless the person has the MANAGE task on the account. Always read live.
PATCH/api/v1/ads/accounts/{adAccountId}Update an ad account
Renames an account or sets its spending limit — Meta's hard stop, counted from the moment it is set: once the account has spent that much, all its ads stop delivering. Returns the same shape as the details endpoint.
Body
namestring- Up to 100 characters.
spendCapnumber | null- Whole currency units; null removes the limit.
Payment methods and closing an account have no API; do those in Meta.
GET/api/v1/ads/treeCampaign tree
The Campaign → Ad set → Ad hierarchy for one ad account, with spend,
impressions, reach, clicks, ctr, cpc and cpm rolled up at every
level. An object that did not deliver in the range reports zeroes rather than
being omitted.
Query parameters
adAccountIdstringRequired- An ad account id, in Meta's act_<digits> form.
sincedate- YYYY-MM-DD. Defaults to 28 days ago.
untildate- YYYY-MM-DD. Defaults to today. Ranges over 730 days are rejected.
accountIduuid- A connected Facebook account.
profileIduuid- Defaults to your key's profile.
GET/api/v1/ads/insightsDaily insights
One point per day for an ad account, or for a single campaign, ad set or ad when
objectId is given.
Query parameters
adAccountIdstringRequired- An ad account id.
objectIdstring- A campaign, ad set or ad id. Defaults to the whole account.
sincedate- YYYY-MM-DD. Defaults to 28 days ago.
untildate- YYYY-MM-DD. Defaults to today.
POST/api/v1/ads/campaignsCreate a campaign
Promotes a post the connected Page already published, creating a campaign, ad set, creative and ad. Everything is created paused. Nothing delivers and nothing spends until you activate it, which is a separate call.
An Idempotency-Key header is required. This is the only endpoint in the API
where a retry has a cost, so the same key replays the original result rather
than creating a second campaign: 200 with the same object ids when the
campaign was built, 409 campaign_create_failed with the original reason when
it failed, and 409 campaign_create_in_progress while it is still being
created. To retry a failed create, send a new key.
Body
adAccountIdstringRequired- The ad account to create in.
pagePostIdstringRequired- The post id alone; the Page half of Meta's story id is server-derived.
dailyBudgetnumberRequired- Whole currency units, as Meta expects: 25 means 25.00.
startDatedateRequired- YYYY-MM-DD.
endDatedateRequired- YYYY-MM-DD, on or after startDate.
campaignNamestringRequired- Shown in Ads Manager.
Responds 201 with the created object ids, Adeli's campaign record (its id is the campaignRecordId below), and a
preview when Meta returns one: Meta's body markup, plus the url, width
and height of the facebook.com preview page it wraps. Embed url in an
iframe that allows scripts; the page renders blank without them. If a step fails, Adeli deletes what it
already created and responds 502 campaign_create_failed with the failing step and any
orphanedObjectIds it could not remove — those are paused, so they cost
nothing, but they are named so you can find them in Ads Manager.
DELETE/api/v1/ads/campaigns/{campaignId}Delete a campaign
Deletes a campaign together with its ad sets and ads, which stops any delivery
immediately. It cannot be undone. The campaign must belong to adAccountId;
otherwise the response is 404 campaign_not_found and nothing is deleted.
Responds 204. Adeli's record of a campaign it created is marked deleted.
Query parameters
adAccountIdstringRequired- The ad account the campaign belongs to.
accountIduuid- A connected Facebook account. Defaults to the profile's.
PUT/api/v1/ads/statusActivate, pause or resume
Sets an ad's or ad set's delivery status. Activating an ad is what starts spending.
Body
adAccountIdstringRequired- The ad account the object belongs to.
objectIdstringRequired- An ad or ad set id.
statusstringRequired- ACTIVE or PAUSED.
campaignRecordIduuid- Keeps Adeli's campaign record in step when the object came from POST `/api/v1/ads/campaigns`.
GET/api/v1/ads/leadsLead forms and submissions
Without formId, the lead generation forms belonging to the connected Page.
With it, that form's submissions, including the field data and the campaign, ad
set and ad each lead came from.
Adeli does not store lead data. Submissions are read from Facebook when you ask for them and are not retained after the response.
Query parameters
formIdstring- A lead form id. Omit to list the Page's forms.
accountIduuid- A connected Facebook account.
profileIduuid- Defaults to your key's profile.