Skip to content

REST API v1 · Resource

Ads

Create ads (always paused), read their results and charges, and manage Facebook Lead Ads forms.

API reference · Ads

Last updated

Endpoints

Paths are relative to https://fliok.com/api/v1. Each endpoint names the scope and the lowest key role it needs; a key without them gets 403 (see Authentication).

Meta ads made in Fliok: Click-to-WhatsApp ads, Instagram ads (a boosted post, or an ad that opens Instagram Direct), and one ad whose button opens WhatsApp or Instagram. Plus Facebook Lead Ads forms. Every change goes through the same code as the dashboard, with the same checks.

  • Early access. Ads open for a workspace once Meta approves Fliok's ads permissions. Until then every /ads endpoint answers 404 not_available, as the dashboard does. Lead Ads are not behind this door.
  • Ads are always created paused. Nothing you create spends money until you publish it.
  • Spending needs ads:spend. Publishing or resuming an ad, raising a budget, and approving a suggestion that moves budget need the ads:spend scope. A key must be made with ads:spend named; no existing key has it, and no role gets it by default. Without it you get 403 insufficient_scope. Pausing, archiving and lowering a budget need only ads:write, so a key can always stop the spend.
  • The same confirmation as the dashboard. To publish or resume, send confirmBudgetMinor equal to the ad's daily budget in minor units (paise, cents). To raise a budget, send it equal to the new budget. A mismatch is 409 budget_mismatch.
  • Plan and add-ons. Creating, publishing and raising budgets need Automation & CRM on your plan (402 otherwise). Instagram ads need the Instagram add-on; ads that open either app also need the WhatsApp + Instagram ads add-on. Pausing and archiving work on any plan.
  • Connecting is a browser flow. Connect the Facebook ad account in the dashboard. GET /integrations/meta-ads gives its connectUrl; DELETE /integrations/meta-ads disconnects it.
  • Not in the API. The AI parts (writing ad copy, AI plans and reviews, Autopilot settings) stay in the dashboard: they are billed from your AI wallet and set how Fliok's AI acts for you. Ad videos are uploaded in the dashboard; images go in by URL with POST /ads/images.

Ads

22
  • GET/ads/accountThe connected Facebook ad account and Page: status, currency, time zone, last sync, Meta's account status. Never the tokenScope ads:read · viewer role or higher
  • GET/adsEvery Meta ad made in Fliok, newest first. ?type=all|whatsapp|instagram|both. Each with kind, status, budget, audience and last resultsScope ads:read · viewer role or higher
  • GET/ads/{id}One ad of any kind: status, daily budget, audience, schedule, creative and last-synced resultsScope ads:read · viewer role or higher
  • GET/ads/analyticsThe Analytics tab: totals against the period before, a daily series, a row per ad and the funnel. ?period=7|28|90 or custom, ?channel=Scope ads:read · viewer role or higher
  • GET/ads/analytics/exportThe Analytics tab's per-ad rows as CSV, with the same query as GET /ads/analyticsScope ads:read · viewer role or higher
  • GET/ads/chargesWhat Meta says the ad account spent this month and last, and how it pays. Payment method for admin keys. ?fresh=1 asks Meta againScope ads:read · viewer role or higher
  • GET/ads/performanceMeta's figures for ?days=7|28 and the period before, joined with each ad's leads in Fliok. ?ad=<id> for one adScope ads:read · viewer role or higher
  • POST/ads/whatsappCreate a Click-to-WhatsApp ad, always paused, through the dashboard's create code. Needs the plan. Upload the image first with POST /ads/imagesScope ads:write · admin role or higher
  • POST/ads/instagramCreate an Instagram ad, always paused: boost one of your posts or open Instagram Direct. Needs the Instagram add-on and the planScope ads:write · admin role or higher
  • POST/ads/bothCreate one ad that opens WhatsApp or Instagram Direct, always paused. Needs the Instagram and WhatsApp + Instagram ads add-ons and the planScope ads:write · admin role or higher
  • POST/ads/{id}/statusPause or archive an ad (ads:write, any plan). Publish or resume it: also needs ads:spend, the plan and confirmBudgetMinor equal to its daily budgetScope ads:write · admin role or higher
  • POST/ads/{id}/budgetChange an ad's daily budget. Lowering needs ads:write; raising also needs ads:spend, the plan and confirmBudgetMinor equal to the new budgetScope ads:write · admin role or higher
  • POST/ads/refreshRe-read every ad's status and results from Meta now. At most once a minute; inside that, throttled is true and stored figures returnScope ads:write · admin role or higher
  • POST/ads/imagesFetch an ad image (JPG or PNG, up to 8 MB) from a public https URL and upload it to the ad account. Returns imageHash and imageKeyScope ads:write · admin role or higher
  • GET/ads/targetingMeta's audience search: ?type=place&q= for cities and regions (optional country) or ?type=interest&q=. Use the results when creating an adScope ads:read · admin role or higher
  • GET/ads/recommendationsFliok's open suggestions for your ads and the recent changes made to them, by a person or by Autopilot. ?ad=<id> for one adScope ads:read · viewer role or higher
  • POST/ads/recommendations/{id}/decisionApprove, dismiss or snooze a suggestion. Approving runs its stored change; approving a budget move also needs ads:spend and confirmBudgetMinorScope ads:write · admin role or higher
  • GET/lead-adsFacebook Lead Ads: the connected Page, whether Fliok gets its leads, and its forms with their questions and settings. Never a tokenScope ads:read · admin role or higher
  • POST/lead-ads/subscribeSubscribe Fliok to the connected Page's leads, so each new lead arrives as a contact and a CRM lead. No bodyScope ads:write · admin role or higher
  • GET/lead-ads/forms/{formId}One Lead Ads form: its questions, how answers map to contact fields, the stage, owner, follow-up and last importScope ads:read · admin role or higher
  • PUT/lead-ads/forms/{formId}Save how a form's answers become a contact and lead: field map, stage, owner and the WhatsApp follow-up templateScope ads:write · admin role or higher
  • POST/lead-ads/forms/{formId}/importImport a form's leads from Meta's last 90 days as contacts and CRM leads. Leads already in Fliok are skippedScope ads:write · admin role or higher

Request bodies

What these endpoints take, field by field. A body that doesn’t match answers 400 naming the field.

POST /ads/whatsapp

JSON body. A Click-to-WhatsApp ad, created paused. Optional Idempotency-Key header.

FieldTypeWhat it is
namerequiredstringThe ad’s name, 1–80 characters.
countriesrequiredstring[]Two-letter country codes, 1–25 (e.g. ["IN"]).
ageMinrequiredintegerYoungest age shown the ad, 18–65.
ageMaxrequiredintegerOldest age, 18–65, not below ageMin.
genderrequiredstringall, men or women.
advantageAudiencerequiredbooleanLet Meta widen the audience when it finds more people likely to reply.
locationsobject[]Cities or regions from GET /ads/targeting?type=place: { type, key, name, countryCode, region }. Each must be in one of the countries.
interestsobject[]Interests from GET /ads/targeting?type=interest: { id, name }.
dailyBudgetrequiredstringThe daily budget in the ad account’s currency, as you would type it ("500"). At least Meta’s minimum.
startTimestringISO 8601 with a zone. Leave out to start when published.
endTimestringISO 8601 with a zone, more than 24 hours after the start.
primaryTextrequiredstringThe ad’s text, up to 1,000 characters.
headlinerequiredstringUp to 100 characters.
greetingrequiredstringThe message customers see when WhatsApp opens, up to 300 characters.
prefillrequiredstringThe message typed for the customer, up to 150 characters.
formatstringimage (default), video, carousel or catalog, where Meta allows it for this kind of ad.
imageHashstringFrom POST /ads/images. Needed for an image ad.
imageKeystringFrom POST /ads/images, with imageHash.
videoobjectA video uploaded in the dashboard. Needed for a video ad.
cardsobject[]A carousel’s 2–10 cards, each with its own image.
leadTagstringA tag put on every contact this ad brings in, up to 40 characters.
planIdstringThe AI plan this ad was made from, if any (marked used).
recommendationIdstringThe suggestion this ad answers, if any (closed when it is made).

Returns 201 { ok, ad } — the ad, paused. Publish it with POST /ads/{id}/status.

POST /ads/instagram

JSON body. An Instagram ad, created paused. Needs the Instagram add-on. Optional Idempotency-Key header.

FieldTypeWhat it is
typerequiredstringboost_post (one of your own posts) or instagram_direct (opens a chat in Instagram Direct).
namerequiredstringThe ad’s name, 1–80 characters.
countriesrequiredstring[]Two-letter country codes, 1–25 (e.g. ["IN"]).
ageMinrequiredintegerYoungest age shown the ad, 18–65.
ageMaxrequiredintegerOldest age, 18–65, not below ageMin.
genderrequiredstringall, men or women.
advantageAudiencerequiredbooleanLet Meta widen the audience when it finds more people likely to reply.
locationsobject[]Cities or regions from GET /ads/targeting?type=place: { type, key, name, countryCode, region }. Each must be in one of the countries.
interestsobject[]Interests from GET /ads/targeting?type=interest: { id, name }.
dailyBudgetrequiredstringThe daily budget in the ad account’s currency, as you would type it ("500"). At least Meta’s minimum.
startTimestringISO 8601 with a zone. Leave out to start when published.
endTimestringISO 8601 with a zone, more than 24 hours after the start.
mediaIdstringboost_post: the post’s id, from GET /instagram/posts/recent.
goalstringboost_post: engagement or traffic.
linkstringboost_post with goal traffic: the https:// address people go to.
callToActionstringboost_post: the button, from Meta’s list (e.g. LEARN_MORE).
primaryTextstringinstagram_direct: the ad’s text, up to 1,000 characters.
greetingstringinstagram_direct: what customers see when the chat opens, up to 300 characters.
iceBreakersstring[]instagram_direct: 1–3 questions customers can tap, up to 80 characters each.
formatstringinstagram_direct: image (default), video, carousel or catalog, where Meta allows it for this kind of ad.
imageHashstringinstagram_direct: From POST /ads/images. Needed for an image ad.
imageKeystringinstagram_direct: From POST /ads/images, with imageHash.
videoobjectinstagram_direct: A video uploaded in the dashboard. Needed for a video ad.
cardsobject[]instagram_direct: A carousel’s 2–10 cards, each with its own image.
planIdstringThe AI plan this ad was made from, if any (marked used).
recommendationIdstringThe suggestion this ad answers, if any (closed when it is made).

Returns 201 { ok, ad } — the ad, paused. Publish it with POST /ads/{id}/status.

POST /ads/both

JSON body. One ad whose button opens WhatsApp or Instagram Direct, created paused. Needs the Instagram and WhatsApp + Instagram ads add-ons. Optional Idempotency-Key header.

FieldTypeWhat it is
namerequiredstringThe ad’s name, 1–80 characters.
countriesrequiredstring[]Two-letter country codes, 1–25 (e.g. ["IN"]).
ageMinrequiredintegerYoungest age shown the ad, 18–65.
ageMaxrequiredintegerOldest age, 18–65, not below ageMin.
genderrequiredstringall, men or women.
advantageAudiencerequiredbooleanLet Meta widen the audience when it finds more people likely to reply.
locationsobject[]Cities or regions from GET /ads/targeting?type=place: { type, key, name, countryCode, region }. Each must be in one of the countries.
interestsobject[]Interests from GET /ads/targeting?type=interest: { id, name }.
dailyBudgetrequiredstringThe daily budget in the ad account’s currency, as you would type it ("500"). At least Meta’s minimum.
startTimestringISO 8601 with a zone. Leave out to start when published.
endTimestringISO 8601 with a zone, more than 24 hours after the start.
primaryTextrequiredstringThe ad’s text, up to 1,000 characters.
headlinerequiredstringUp to 100 characters.
greetingrequiredstringWhat customers see when the chat opens, up to 300 characters.
iceBreakersrequiredstring[]1–3 questions customers can tap, up to 80 characters each.
formatstringimage (default), video, carousel or catalog, where Meta allows it for this kind of ad.
imageHashstringFrom POST /ads/images. Needed for an image ad.
imageKeystringFrom POST /ads/images, with imageHash.
videoobjectA video uploaded in the dashboard. Needed for a video ad.
cardsobject[]A carousel’s 2–10 cards, each with its own image.
planIdstringThe AI plan this ad was made from, if any (marked used).
recommendationIdstringThe suggestion this ad answers, if any (closed when it is made).

Returns 201 { ok, ad } — the ad, paused. Publish it with POST /ads/{id}/status.

POST /ads/{id}/status

JSON body. pause and archive need ads:write. publish and resume also need ads:spend and the plan. An archived ad can’t be turned back on. Optional Idempotency-Key header.

FieldTypeWhat it is
actionrequiredstringpause, archive, publish or resume. resume is for an ad that has run before.
confirmBudgetMinorintegerpublish and resume: the ad’s daily budget in minor units, exactly as GET /ads/{id} shows it (dailyBudgetMinor).

Returns { ok, ad } — the ad with the status Meta reports.

POST /ads/{id}/budget

JSON body. Lowering needs ads:write; raising also needs ads:spend and the plan. Up to 12 changes an hour. Optional Idempotency-Key header.

FieldTypeWhat it is
dailyBudgetrequiredstringThe new daily budget in the ad’s currency, as you would type it ("650").
confirmBudgetMinorintegerWhen raising: the new budget in minor units (65000 for ₹650).

Returns { ok, actionId, beforeMinor, afterMinor }

POST /ads/images

JSON body. Fliok downloads the image from a public https:// address (private and internal addresses are refused) and uploads it to your ad account.

FieldTypeWhat it is
urlrequiredstringThe image’s https:// address. JPG or PNG, up to 8 MB.
usestringsingle (default), card (a carousel card) or cover (a video’s cover).
rationumberFor cards: the width-to-height shape all cards share (1 for square).

Returns { ok, imageHash, imageKey, width, height } — pass imageHash and imageKey to a create call.

POST /ads/recommendations/{id}/decision

JSON body. Approving runs the suggestion’s own stored change. A budget move also needs ads:spend. Optional Idempotency-Key header.

FieldTypeWhat it is
actionrequiredstringapprove, dismiss or snooze.
confirmBudgetMinorintegerApproving a budget move: the raised ad’s new budget in minor units, as the suggestion shows it.

Returns { ok, status, actionId, recommendations }, or { ok, status: "open_form", href } for a “make a new ad” suggestion (finish it in the dashboard).

PUT /lead-ads/forms/{formId}

JSON body. The whole setting for one form; send every field.

FieldTypeWhat it is
pageIdrequiredstringThe connected Page’s id, from GET /lead-ads.
formNamestringThe form’s name, for your records.
fieldMaprequiredobjectQuestion key → contact field (as GET /lead-ads lists in contactFields). Up to 100.
stageIdrequiredstringThe CRM stage new leads start in, or null for the first stage.
ownerIdrequiredstringThe member new leads are given to, or null.
followUprequiredobject{ enabled, templateName, language, consentQuestion }: an approved WhatsApp template sent to new leads who agreed in the form.

Returns { ok: true }

Examples

Create a Click-to-WhatsApp ad (paused)

curl -X POST "https://fliok.com/api/v1/ads/images" \
  -H "Authorization: Bearer wa_YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"url":"https://cdn.ashasarees.in/diwali.jpg"}'

curl -X POST "https://fliok.com/api/v1/ads/whatsapp" \
  -H "Authorization: Bearer wa_YOUR_API_KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: diwali-ad-1" \
  -d '{"name":"Diwali sarees","countries":["IN"],"ageMin":25,"ageMax":55,"gender":"women",
       "advantageAudience":true,"dailyBudget":"500","primaryText":"New Banarasi silk, 20% off till Diwali.",
       "headline":"Diwali sale","greeting":"Hi! Which saree caught your eye?","prefill":"Show me the Diwali sarees",
       "format":"image","imageHash":"7d1c0f9e2b4a","imageKey":"ad-images/7c1e2d4a/1080x1080-3f2a.jpg"}'

Publish it (needs ads:spend), then pause it

curl -X POST "https://fliok.com/api/v1/ads/5b0e8c4a-2f71-4d0b-9a63-0c1e7f2d9b18/status" \
  -H "Authorization: Bearer wa_YOUR_SPEND_KEY" -H "Content-Type: application/json" \
  -d '{"action":"publish","confirmBudgetMinor":50000}'

curl -X POST "https://fliok.com/api/v1/ads/5b0e8c4a-2f71-4d0b-9a63-0c1e7f2d9b18/status" \
  -H "Authorization: Bearer wa_YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"action":"pause"}'

Read your ads and their results

curl "https://fliok.com/api/v1/ads?type=whatsapp" \
  -H "Authorization: Bearer wa_YOUR_API_KEY"

curl "https://fliok.com/api/v1/ads/analytics?period=28" \
  -H "Authorization: Bearer wa_YOUR_API_KEY"

Import a Lead Ads form’s leads

curl "https://fliok.com/api/v1/lead-ads" \
  -H "Authorization: Bearer wa_YOUR_ADMIN_KEY"

curl -X POST "https://fliok.com/api/v1/lead-ads/forms/1029384756/import" \
  -H "Authorization: Bearer wa_YOUR_ADMIN_KEY"

Rate limits

The buckets these endpoints use. Burst is how many requests you can make back-to-back from a full bucket; sustained is how fast it refills.

BucketEndpointsBurstSustained
Reads/messages · /conversations · /contacts · /templates · /phone-numbers · GET /webhooks · Instagram, LinkedIn, ads and catalog reads · GET /payment-requests/{id}60060 / sec
Ad budgetsPOST /ads/{id}/budget1212 / hour
Ad imagesPOST /ads/images301 / 2 sec
Ad suggestionsPOST /ads/recommendations/{id}/decision3030 / 10 min
Ad charges from MetaGET /ads/charges?fresh=131 / min
Lead Ads importPOST /lead-ads/forms/{formId}/import33 / 10 min

Every limit, the RateLimit-* headers and what to do on a 429: Rate limits.