REST API v1 · Resource
LinkedIn ads
Read LinkedIn ad results and audiences, search the Ad Library, and boost posts.
API reference · LinkedIn 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).
LinkedIn is a paid add-on on the Basic plan and up. Until your workspace has it, these endpoints answer 402 linkedin_addon_required (or 403 linkedin_unavailable when nothing is on offer), exactly as the dashboard does. Connect LinkedIn in Integrations first. Every endpoint runs the dashboard’s own code: the same roles, checks, limits and audit log.
- Each part needs its LinkedIn product. Ad results and drafts need
ads, the Ad Libraryadlibrary, boostsboost. Lead Sync, the Conversions API and Matched Audiences need LinkedIn’sleads,conversionsandaudiencesproducts, which are not switched on yet: until they are, those endpoints answerfeature: "off"or the dashboard’s refusal. - Nothing launches by itself. Message Ads, Conversation Ads and Sponsored Content are made as drafts with no bid. You review and launch them in LinkedIn Campaign Manager. Pausing a campaign needs
ads:write. - Spending needs ads:spend. Starting a boost (LinkedIn has no paused boost: it can serve at once) and resuming a campaign also need the
ads:spendscope. A key must be made withads:spendnamed; no existing key has it. Without it you get403 insufficient_scopebefore anything is read. A boost then takes the same three steps as the dashboard:init,previewwith your total budget, and the start withconfirmSpend: trueand the exact goal, dates, amount and currency of that preview. - No body:
POST /linkedin/ads/refresh,POST …/campaigns/{campaignId}/pauseand/resume, andPOST /linkedin/audiences/{id}/sync. - Not in the API: raising a campaign’s budget or bid (Fliok never changes what a LinkedIn campaign may spend; do it in Campaign Manager), Fliok AI’s outreach planner (a dashboard helper that bills the AI wallet; make the draft with
POST /linkedin/ads/message-ads), and connecting LinkedIn (a person signs in to LinkedIn in Integrations). Posts and events are on the LinkedIn page.
LinkedIn ads
35- GET
/linkedin/adsLinkedIn ad results for ?days=7|30|90: each campaign’s spend, impressions, clicks, leads and cost per lead, totals per currency, and the CRM’s LinkedIn leads and winsScopelinkedin:read· viewer role or higherNeeds an API key - GET
/linkedin/ads/accountsYour LinkedIn ad accounts, whether Fliok reports on each, and the last sync. Never a tokenScopelinkedin:read· viewer role or higherNeeds an API key - PATCH
/linkedin/ads/accountsReport on one ad account, or stop (`{ account, report }`). Switching one on needs the LinkedIn add-on; switching off never doesScopelinkedin:write· admin role or higherNeeds an API key - POST
/linkedin/ads/refreshRead the ad accounts, campaigns and daily results from LinkedIn now instead of at the next 6-hourly sync. Three a quarter-hourScopelinkedin:write· admin role or higherNeeds an API key - GET
/linkedin/ads/demographicsWho saw your ads (job titles, seniority, industries, company sizes, locations) for an ?account= or ?campaign=, read live and kept an hourScopelinkedin:read· viewer role or higherNeeds an API key - POST
/linkedin/ads/campaigns/{campaignId}/pausePause one campaign Fliok has read (its numeric id). Stops spend at once, so it needs no add-on and no ads:spend. AuditedScopeads:write· admin role or higherNeeds an API key - POST
/linkedin/ads/campaigns/{campaignId}/resumeResume one paused campaign: it SPENDS again at its budget. Also needs ads:spend (no key has it unless made with it named) and the add-onScopeads:write· admin role or higherNeeds an API key - GET
/linkedin/ad-librarySearch LinkedIn’s Ad Library: ?kind=ads|jobs|partnerships with a keyword or advertiser name, country and days. Kept an hour per searchScopelinkedin:read· viewer role or higherNeeds an API key - GET
/linkedin/ads/message-ads/optionsWhat a message ad can use: the ad accounts you may create campaigns in, the sender and the languagesScopelinkedin:read· admin role or higherNeeds an API key - GET
/linkedin/ads/message-ads/locationsLinkedIn locations to target, by name (?q=). Returns the urn:li:geo ids a message ad’s `locations` takesScopelinkedin:read· admin role or higherNeeds an API key - GET
/linkedin/ads/audienceLinkedIn’s values for one targeting facet (?facet=titles|seniorities|industries|… and ?q=), with the URNs an `audience` takesScopelinkedin:read· admin role or higherNeeds an API key - POST
/linkedin/ads/audience/countHow many LinkedIn members an audience reaches, and whether that meets LinkedIn’s minimum. Read-only: nothing is madeScopeads:write· admin role or higherNeeds an API key - POST
/linkedin/ads/message-adsMake a Message Ad or Conversation Ad as a DRAFT campaign in your ad account. Nothing launches and no bid is set. Optional WhatsApp buttonScopeads:write· admin role or higherNeeds an API key - GET
/linkedin/ads/sponsored-content/optionsWhat Sponsored Content can use: the ad accounts you may create campaigns in and the company pages you administerScopelinkedin:read· admin role or higherNeeds an API key - POST
/linkedin/ads/sponsored-contentQueue a Sponsored Content ad (image, video, document or lead gen form) as a DRAFT from an uploaded file. 202 with a job to followScopeads:write· admin role or higherNeeds an API key - GET
/linkedin/ads/sponsored-content/{jobId}How a Sponsored Content draft is getting on: working (with the step), done (what was made) or failed (why, and what exists)Scopelinkedin:read· admin role or higherNeeds an API key - GET
/linkedin/boostBoost status of up to 100 of your published page posts (?posts=id,id), with results for boosted ones. `feature` says off or reconnectScopelinkedin:read· viewer role or higherNeeds an API key - POST
/linkedin/boost/{id}/initStep 1 of a boost: is the post eligible, the ad account, billing, currency, goals, default dates and the most it may cost. Spends nothingScopeads:write· admin role or higherNeeds an API key - POST
/linkedin/boost/{id}/previewStep 2: LinkedIn’s forecast for a goal, dates and a total budget. The last preview with `amount` is what step 3 must echo. Spends nothingScopeads:write· admin role or higherNeeds an API key - POST
/linkedin/boost/{id}Step 3: start the boost — it SPENDS at once. Also needs ads:spend, `confirmSpend: true` and the previewed goal, dates, amount and currencyScopeads:write· admin role or higherNeeds an API key - DELETE
/linkedin/boost/{id}Stop a running boost (`{ confirmStop: true }`). LinkedIn deletes its campaign; it is not a pauseScopeads:write· admin role or higherNeeds an API key - GET
/linkedin/ads/outreachYour LinkedIn outreach: Conversation Ads with a WhatsApp button, the chats and leads each brought, and its Fliok AI playbookScopelinkedin:read· admin role or higherNeeds an API key - PATCH
/linkedin/ads/outreach/{id}Switch one outreach’s Fliok AI playbook on or off, or change its instructions (`{ on?, instructions? }`). AuditedScopeads:write· admin role or higherNeeds an API key - GET
/linkedin/leadsLead Sync: on or off, the LinkedIn lead gen forms found and each one’s WhatsApp follow-up. Leads arrive in the CRM as contactsScopelinkedin:read· viewer role or higherNeeds an API key - PATCH
/linkedin/leadsSwitch Lead Sync on or off (`{ leadSync }`). On needs the LinkedIn add-on and LinkedIn’s Lead Sync productScopelinkedin:write· admin role or higherNeeds an API key - PATCH
/linkedin/leads/forms/{formId}Set one lead gen form’s WhatsApp follow-up: on or off, the approved template and language, and the consent question it needsScopelinkedin:write· admin role or higherNeeds an API key - GET
/linkedin/conversionsThe Conversions API setup: mode, ad account, the rule for each CRM event, on or off, and recent sends. Never the tokenScopelinkedin:read· viewer role or higherNeeds an API key - PUT
/linkedin/conversionsSave the Conversions API setup: token or OAuth mode, ad account, a rule per event, on or off. A token is stored encrypted, never returnedScopelinkedin:write· admin role or higherNeeds an API key - DELETE
/linkedin/conversionsRemove the Conversions API setup and its stored token. Nothing more is sent to LinkedInScopelinkedin:write· admin role or higherNeeds an API key - GET
/linkedin/conversions/rulesThe conversion rules in the saved ad account, read from LinkedIn, to pick one per CRM eventScopelinkedin:read· admin role or higherNeeds an API key - POST
/linkedin/conversions/rulesMake a conversion rule at LinkedIn for one CRM event (lead, qualified, won, payment) in the saved ad accountScopelinkedin:write· admin role or higherNeeds an API key - GET
/linkedin/audiencesYour Matched Audiences synced from CRM contacts: status, contacts sent and matched, the ad accounts and what can go in oneScopelinkedin:read· viewer role or higherNeeds an API key - POST
/linkedin/audiencesA new Matched Audience from CRM tags and stages. Its contacts’ hashed emails go to LinkedIn from the next syncScopelinkedin:write· admin role or higherNeeds an API key - DELETE
/linkedin/audiences/{id}Delete one audience in Fliok and at LinkedInScopelinkedin:write· admin role or higherNeeds an API key - POST
/linkedin/audiences/{id}/syncSync one audience now instead of at the next hourly run. Six an hourScopelinkedin:write· admin role or higherNeeds an API key
Request bodies
What these endpoints take, field by field. A body that doesn’t match answers 400 naming the field.
PATCH /linkedin/ads/accounts
JSON body. Admin keys. Switching reporting on needs the LinkedIn add-on; switching it off never does.
| Field | Type | What it is |
|---|---|---|
accountrequired | string | The ad account, "urn:li:sponsoredAccount:<number>", from GET /linkedin/ads/accounts. |
reportrequired | boolean | true to read this account's results, false to stop. |
Returns 200 { ok, account, report }
POST /linkedin/ads/audience/count
JSON body. Read-only: nothing is made at LinkedIn. Facets: locations, titles, seniorities, industries, functions, skills, companySizes, companies (URNs from GET /linkedin/ads/audience).
| Field | Type | What it is |
|---|---|---|
audiencerequired | object | Facet → array of up to 30 URNs, e.g. { "locations": ["urn:li:geo:102713980"], "titles": ["urn:li:title:1"] }. Locations are required. |
Returns 200 { count, meetsMinimum, … }
POST /linkedin/ads/message-ads
JSON body. Admin keys with ads:write. Makes a DRAFT campaign group, campaign, message and ad; nothing launches and no bid is set. Send an `Idempotency-Key` so a retry never makes a second draft.
| Field | Type | What it is |
|---|---|---|
kindrequired | "message" | "conversation" | A Message Ad (one message, one button) or a Conversation Ad (an opening and up to five buttons). |
accountrequired | string | The ad account URN, from GET /linkedin/ads/message-ads/options. |
namerequired | string | The campaign name, up to 200 characters. |
subjectrequired | string | The message subject, up to 60 characters. |
body | string | Message Ad text, up to 1,500 characters. |
ctaText | string | Message Ad button text, up to 20 characters. |
ctaUrl | string | Message Ad button link (https). |
opening | string | Conversation Ad opening message, up to 500 characters. |
buttons | object[] | Conversation Ad buttons, up to 5: { text, action: "url", url } | { text, action: "reply", reply } | { text, action: "whatsapp", message }. One WhatsApp button at most; it opens a tracked link to your WhatsApp number with `message` typed. |
locationsrequired | string[] | 1–20 "urn:li:geo:<number>" from GET /linkedin/ads/message-ads/locations. |
audience | object | Extra targeting with names: facet → [{ urn, name }], up to 30 each. Facets: locations, titles, seniorities, industries, functions, skills, companySizes, companies (URNs from GET /linkedin/ads/audience). |
playbook | string | With a WhatsApp button: how Fliok AI answers the chats this ad opens. The draft is kept as an outreach. |
localerequired | string | Language, like "en_US". |
dailyBudgetrequired | string | Daily budget in the account currency, like "500". Saved on the draft; nothing spends until you launch it. |
startAtrequired | number | Start, Unix milliseconds. A past start moves to now. |
endAtrequired | number | null | End, Unix milliseconds, or null to run until stopped. |
notPoliticalrequired | true | Confirms this is not political advertising. |
Returns 200 { ok, kind, name, accountUrn, accountName, created: { campaignGroupUrn, campaignUrn, … }, campaignManagerUrl, startAt, outreach? }
POST /linkedin/ads/sponsored-content
JSON body. Admin keys with ads:write. Queues a DRAFT Sponsored Content ad; follow it at GET /linkedin/ads/sponsored-content/{jobId}. Upload the file first, as for a LinkedIn post. Send an `Idempotency-Key`.
| Field | Type | What it is |
|---|---|---|
formatrequired | "image" | "video" | "document" | "leadgen" | The ad format. "leadgen" needs `leadForm`. |
accountrequired | string | The ad account URN, from GET /linkedin/ads/sponsored-content/options. |
pagerequired | string | The company page it runs as, "urn:li:organization:<number>". |
mediaKeyrequired | string | The uploaded file's key (the LinkedIn post media upload). |
namerequired | string | The campaign name. |
introTextrequired | string | The text above the ad, up to 3,000 characters. |
headlinerequired | string | The headline, up to 200 characters. |
ctaLabel | string | Button label, like "LEARN_MORE". |
landingUrl | string | Where the ad leads (https). Not for lead gen. |
leadForm | object | For "leadgen": { headline, description?, privacyPolicyUrl, thankYouMessage, thankYouUrl }. |
locationsrequired | string[] | 1–20 "urn:li:geo:<number>". |
localerequired | string | Language, like "en_US". |
dailyBudgetrequired | string | Daily budget in the account currency. Nothing spends until you launch it. |
startAtrequired | number | Start, Unix milliseconds. |
endAtrequired | number | null | End, Unix milliseconds, or null. |
notPoliticalrequired | true | Confirms this is not political advertising. |
Returns 202 { ok, jobId, format, name, accountUrn }
PATCH /linkedin/ads/outreach/{id}
JSON body, at least one field. Admin keys with ads:write.
| Field | Type | What it is |
|---|---|---|
on | boolean | Fliok AI answers this outreach's chats by its playbook, or not. |
instructions | string | The playbook's new instructions. |
Returns 200 { ok, on, … }
POST /linkedin/boost/{id}/init
Empty JSON body `{}`. Step 1 of a boost: `{id}` is a Fliok LinkedIn post id, a published post made as your company page. LinkedIn may create a sponsored account for the page. Spends nothing.
| Field | Type | What it is |
|---|
Returns 200 { billingConfigured, billingUrl, currencyCode, goals, defaultGoal, defaultSchedule, maxTotalBudget }
POST /linkedin/boost/{id}/preview
JSON body. Step 2. Spends nothing. The last preview WITH `amount` is what step 3 must echo.
| Field | Type | What it is |
|---|---|---|
goalrequired | string | One of the goals from step 1 (e.g. "ENGAGEMENT", "WEBSITE_VISIT", "LEAD_GENERATION"). |
schedulerequired | object | { start, end }, Unix milliseconds. |
amount | string | Total budget in the account currency, like "5000". Leave it out for LinkedIn's suggestions only. |
Returns 200 { currencyCode, audienceName, audienceCount, forecast, suggestedBudgets, maxTotalBudget, minDailyBudget, chosen }
POST /linkedin/boost/{id}
JSON body. Step 3: starts the boost, which SPENDS. Needs ads:spend as well as ads:write. Every field must equal the last preview with a budget. Send an `Idempotency-Key`: Fliok sends the create to LinkedIn once and never retries it.
| Field | Type | What it is |
|---|---|---|
confirmSpendrequired | true | You confirm this spends money. |
goalrequired | string | The previewed goal. |
schedulerequired | object | The previewed { start, end }. |
amountrequired | string | The previewed total budget. |
currencyCoderequired | string | The ad account currency, like "INR". |
callToAction | object | Lead generation only: { label, target } with an https target. |
Returns 200 { ok, status: "IN_REVIEW" } · 409 start_again / preview_first / billing_required / boost_in_progress · 502 outcome_unknown (check the status before trying again)
DELETE /linkedin/boost/{id}
JSON body. Stops a running boost: LinkedIn deletes its campaign (it is not a pause).
| Field | Type | What it is |
|---|---|---|
confirmStoprequired | true | You confirm the boost stops for good. |
Returns 200 { ok } · 409 not_running
PATCH /linkedin/leads
JSON body. Admin keys. Switching Lead Sync on needs the add-on and LinkedIn's Lead Sync product.
| Field | Type | What it is |
|---|---|---|
leadSyncrequired | boolean | Bring LinkedIn lead gen form leads into the CRM, or stop. |
Returns 200 { ok, leadSync, … }
PATCH /linkedin/leads/forms/{formId}
JSON body. Admin keys. `{formId}` is the form's id from GET /linkedin/leads.
| Field | Type | What it is |
|---|---|---|
followUp.enabledrequired | boolean | Send a WhatsApp template to each new lead from this form. |
followUp.templateNamerequired | string | null | An approved template's name. |
followUp.languagerequired | string | null | The template's language, like "en". |
followUp.consentQuestionIdrequired | string | null | The form question where the lead agreed to WhatsApp messages. |
Returns 200 { ok }
PUT /linkedin/conversions
JSON body. Admin keys. Turning it on needs the add-on. A token sent here is stored encrypted and never returned.
| Field | Type | What it is |
|---|---|---|
moderequired | "token" | "oauth" | Send with a Conversions API token you paste, or with the connected LinkedIn account. |
token | string | null | The Conversions API token (mode "token"). Leave it out to keep the saved one. |
adAccountrequired | string | The ad account URN conversions belong to. |
rules | object | CRM event → conversion rule URN or null: lead, qualified, won, payment. |
enabledrequired | boolean | Send conversions, or not. |
Returns 200 { configured, mode, tokenSaved, tokenHint, adAccountUrn, rules, enabled, … }
POST /linkedin/conversions/rules
JSON body. Admin keys. Makes a conversion rule at LinkedIn in the saved ad account. Send an `Idempotency-Key`.
| Field | Type | What it is |
|---|---|---|
eventrequired | "lead" | "qualified" | "won" | "payment" | The CRM event the rule counts. |
Returns 201 { rule: { urn, name, type } }
POST /linkedin/audiences
JSON body. Admin keys. Contacts with any of the tags or in any of the stages go to LinkedIn as hashed emails from the next sync. Send an `Idempotency-Key`.
| Field | Type | What it is |
|---|---|---|
namerequired | string | The audience name, up to 100 characters. |
adAccountUrnrequired | string | The ad account it is made in. |
tags | string[] | Up to 50 contact tags. |
stageIds | string[] | Up to 20 lead stage ids. |
Returns 201 { audience: { id, name, adAccountUrn, tags, stageIds } }
Examples
Read your LinkedIn ad results
curl "https://fliok.com/api/v1/linkedin/ads?days=30" \
-H "Authorization: Bearer wa_YOUR_API_KEY"// 200 OK — read from Fliok's 6-hourly sync; money in minor units (paise)
{
"linkedin": {
"days": 30,
"since": "2026-09-30",
"until": "2026-10-29",
"campaigns": [
{
"id": "381944012",
"urn": "urn:li:sponsoredCampaign:381944012",
"name": "Diwali offer — founders, Mumbai",
"status": "ACTIVE",
"accountUrn": "urn:li:sponsoredAccount:512830044",
"accountName": "Asha Sarees",
"currency": "INR",
"spendMinor": 1845000,
"impressions": 41210,
"clicks": 612,
"ctr": 0.0149,
"leads": 37,
"conversions": 9,
"costPerLeadMinor": 49865
}
],
"totals": [{ "currency": "INR", "spendMinor": 1845000, "impressions": 41210, "clicks": 612, "leads": 37, "conversions": 9 }],
"crm": { "leads": 41, "won": 6 },
"syncedAt": "2026-10-29T06:00:12.000Z",
"running": false,
"accounts": 1
},
"canManage": true,
"planLocked": false
}Search LinkedIn’s Ad Library
curl "https://fliok.com/api/v1/linkedin/ad-library?kind=ads&keyword=saree&country=IN&days=30" \
-H "Authorization: Bearer wa_YOUR_API_KEY"// 200 OK — kept an hour per search; ?start= takes "next" for the next page
{
"kind": "ads",
"rows": [
{
"id": "601123987",
"url": "https://www.linkedin.com/ad-library/detail/601123987",
"advertiserName": "Kanchi Weaves",
"payer": "Kanchi Weaves Pvt Ltd",
"format": "SPONSORED_STATUS_UPDATE",
"formatLabel": "Single image",
"firstSeen": "2026-10-02T00:00:00.000Z",
"lastSeen": "2026-10-27T00:00:00.000Z",
"countries": [{ "country": "IN", "share": 1 }]
}
],
"start": 0,
"count": 1,
"total": 1,
"hasMore": false,
"next": 1,
"days": 30
}Make a Conversation Ad as a draft, with a WhatsApp button
curl -X POST "https://fliok.com/api/v1/linkedin/ads/message-ads" \
-H "Authorization: Bearer wa_YOUR_API_KEY" \
-H "Idempotency-Key: diwali-founders-1" \
-H "Content-Type: application/json" \
-d '{
"kind": "conversation",
"account": "urn:li:sponsoredAccount:512830044",
"name": "Diwali offer — founders, Mumbai",
"subject": "A Diwali gift for your team",
"opening": "Hi! We make handwoven sarees for corporate gifting. Want the Diwali catalogue?",
"buttons": [{ "text": "Chat on WhatsApp", "action": "whatsapp", "message": "Hi, please send the Diwali catalogue" }],
"locations": ["urn:li:geo:106164952"],
"playbook": "Share the catalogue, ask team size and delivery date, offer a call.",
"locale": "en_US",
"dailyBudget": "1500",
"startAt": 1761955200000,
"endAt": null,
"notPolitical": true
}'// 200 OK — a DRAFT: nothing runs until you launch it in Campaign Manager
{
"ok": true,
"kind": "conversation",
"name": "Diwali offer — founders, Mumbai",
"accountUrn": "urn:li:sponsoredAccount:512830044",
"accountName": "Asha Sarees",
"created": {
"campaignGroupUrn": "urn:li:sponsoredCampaignGroup:701244",
"campaignUrn": "urn:li:sponsoredCampaign:381990311",
"conversationUrn": "urn:li:sponsoredConversation:55120",
"inMailContentUrn": null,
"creativeUrn": "urn:li:sponsoredCreative:902211"
},
"campaignManagerUrl": "https://www.linkedin.com/campaignmanager/accounts/512830044/campaigns/381990311",
"startAt": 1761955200000,
"outreach": { "id": "0b6c8f3e-2f1a-4d7e-9c55-1a2b3c4d5e6f", "aiOn": true }
}Boost a page post (needs ads:spend)
# 1. Is it eligible, and what may it cost? (spends nothing)
curl -X POST "https://fliok.com/api/v1/linkedin/boost/7d0e5a52-6b1f-4c1e-8a3e-0c9d2f4b7a10/init" \
-H "Authorization: Bearer wa_YOUR_SPEND_KEY" -H "Content-Type: application/json" -d '{}'
# 2. Preview with your total budget (spends nothing)
curl -X POST "https://fliok.com/api/v1/linkedin/boost/7d0e5a52-6b1f-4c1e-8a3e-0c9d2f4b7a10/preview" \
-H "Authorization: Bearer wa_YOUR_SPEND_KEY" -H "Content-Type: application/json" \
-d '{ "goal": "ENGAGEMENT", "schedule": { "start": 1761955200000, "end": 1762560000000 }, "amount": "5000" }'
# 3. Start it: echo the preview exactly. This spends.
curl -X POST "https://fliok.com/api/v1/linkedin/boost/7d0e5a52-6b1f-4c1e-8a3e-0c9d2f4b7a10" \
-H "Authorization: Bearer wa_YOUR_SPEND_KEY" -H "Idempotency-Key: boost-diwali-1" -H "Content-Type: application/json" \
-d '{ "confirmSpend": true, "goal": "ENGAGEMENT", "schedule": { "start": 1761955200000, "end": 1762560000000 }, "amount": "5000", "currencyCode": "INR" }'// 1 → 200 OK
{ "billingConfigured": true, "billingUrl": null, "currencyCode": "INR", "goals": ["ENGAGEMENT", "WEBSITE_VISIT"], "defaultGoal": "ENGAGEMENT",
"defaultSchedule": { "start": 1761955200000, "end": 1762560000000 }, "maxTotalBudget": { "amount": "50000", "currencyCode": "INR" } }
// 2 → 200 OK
{ "currencyCode": "INR", "audienceName": "Followers and people like them", "audienceCount": 184000,
"forecast": { "impressions": { "low": 9800, "high": 14200 } }, "suggestedBudgets": [{ "amount": { "amount": "4000", "currencyCode": "INR" } }],
"maxTotalBudget": { "amount": "50000", "currencyCode": "INR" }, "minDailyBudget": { "amount": "100", "currencyCode": "INR" },
"chosen": { "goal": "ENGAGEMENT", "schedule": { "start": 1761955200000, "end": 1762560000000 }, "budget": { "amount": "5000", "currencyCode": "INR" } } }
// 3 → 200 OK (a key without ads:spend gets 403 insufficient_scope, required "ads:spend")
{ "ok": true, "status": "IN_REVIEW" }Sync CRM contacts to a LinkedIn Matched Audience
curl -X POST "https://fliok.com/api/v1/linkedin/audiences" \
-H "Authorization: Bearer wa_YOUR_API_KEY" \
-H "Idempotency-Key: aud-hot-leads" \
-H "Content-Type: application/json" \
-d '{ "name": "Hot leads — Mumbai", "adAccountUrn": "urn:li:sponsoredAccount:512830044", "tags": ["hot", "mumbai"] }'// 201 Created — hashed emails go to LinkedIn from the next hourly sync
{
"audience": {
"id": "c1f0a9e2-7b3d-4e55-8a10-9d8e7f6a5b4c",
"name": "Hot leads — Mumbai",
"adAccountUrn": "urn:li:sponsoredAccount:512830044",
"tags": ["hot", "mumbai"],
"stageIds": []
}
}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.
| Bucket | Endpoints | Burst | Sustained |
|---|---|---|---|
| Reads | /messages · /conversations · /contacts · /templates · /phone-numbers · GET /webhooks · Instagram, LinkedIn, ads and catalog reads · GET /payment-requests/{id} | 600 | 60 / sec |
| LinkedIn ad results refresh | POST /linkedin/ads/refresh | 3 | 3 / 15 min |
| LinkedIn campaign pause and resume | POST /linkedin/ads/campaigns/{campaignId}/pause · /resume | 20 | 20 / 10 min |
| LinkedIn draft ads | POST /linkedin/ads/message-ads · POST /linkedin/ads/sponsored-content (each its own bucket) | 10 | 10 / hour |
| LinkedIn Ad Library | GET /linkedin/ad-library | 20 | 20 / min |
| LinkedIn boosts | POST /linkedin/boost/{id} · DELETE /linkedin/boost/{id} (preview and init: 30, then 1 / 2 sec) | 20 | 1 / 5 sec |
| LinkedIn audiences | POST /linkedin/audiences (10 / 10 min) · DELETE /linkedin/audiences/{id} (20 / 10 min) · POST /linkedin/audiences/{id}/sync | 6 | 6 / hour |
Every limit, the RateLimit-* headers and what to do on a 429: Rate limits.