Skip to main content
Socialift
Documentation sections
SDK reference

Meta Marketing API Python SDK reference

The Ads client in the Socialift Python SDK wraps Meta's Marketing API: ad accounts, targeting search and reach estimates, campaigns, ad sets, creatives and ads, custom and lookalike audiences, and insights. Campaigns, ad sets and ads are created PAUSED, so nothing spends until you call set_status(..., "ACTIVE"). All methods are async and take a user access token.

from socialift import Ads35 methodsas of socialift 1.3.0Updated:

How do I create an Ads client?

Ads takes your Meta app secret as app_secret; with it, every request carries appsecret_proof. Ads.from_env() reads it from FACEBOOK_APP_SECRET (the same variable Facebook.from_env() uses) and the API version from META_GRAPH_VERSION. Unlike the other clients, a missing secret is not an error: it stays empty and requests go out without appsecret_proof. The license key comes from SOCIALIFT_LICENSE_KEY.

Methods take a user access token (not a Page token): ads_read for reading, ads_management for creating and changing objects. For production use, Meta requires App Review for both permissions.

Money safety: campaigns, ad sets, ads and boost_post() objects are created PAUSED, and delivery_estimate() spends nothing. Budget arguments ending in _major are in the ad account's currency and are multiplied by CURRENCY_OFFSET (100) before sending. Meta uses offset 1 for some currencies (JPY, KRW, IDR, VND, HUF and others), so for those accounts divide the amount by 100 first. UZS is not in Meta's list of ad account currencies.

The default API version is DEFAULT_GRAPH_VERSION (v26.0). Meta supports each version for at least two years from release, and an older version expires two years after the next one launches; calls to an expired version are automatically redirected to the oldest version still supported. Pass graph_version= if you need a different one, and check the date on Meta's versions page.

python
import asyncio
import os

from socialift import Ads

# From the environment: ads = Ads.from_env()
# (FACEBOOK_APP_SECRET, META_GRAPH_VERSION)
ads = Ads(
    app_secret=os.environ["FACEBOOK_APP_SECRET"],
    graph_version="v26.0",  # check Meta's versions page
)


async def main():
    # your own variable: a user token with ads_read
    user_token = os.environ["META_USER_TOKEN"]
    async with ads:
        for account in await ads.ad_accounts(user_token):
            print(account.id, account.name, account.currency, account.is_active)


asyncio.run(main())

Client and keys

Creating the client and reading the Meta app secret from environment variables.

from_env

from_env

classmethod

Creates the client from environment variables: FACEBOOK_APP_SECRET (for appsecret_proof) and META_GRAPH_VERSION. Extra keyword arguments (timeout, retry, session, license_key) are passed to the constructor.

Ads.from_env(**kwargs) -> Ads
  • Unlike the other clients it does not fail on an empty key: without FACEBOOK_APP_SECRET the app_secret stays empty and no appsecret_proof is attached. If your Meta app requires the app secret, such requests are rejected.
  • Without META_GRAPH_VERSION the SDK default version is used; override it inline with Ads.from_env(graph_version="...").
  • No access token is read here — it is passed as an argument to every method.

Ad accounts and pixels

Find the ad account to work in and its pixels.

ad_accountspixels

Lists the ad accounts the user's token can access as AdAccount objects with id, name, currency and status. Usually the first call, since most other methods need an ad_account_id.

await ads.ad_accounts(token: str) -> list[socialift.ads.AdAccount]
  • Needs a user access token (not a Page token) with ads_read.
  • Returns a single page of up to 50 accounts.
  • is_active is True when Meta's account_status equals 1.
  • Budgets are in the account's currency; UZS is not in Meta's list of ad account currencies.

Required permissions:ads_read

Example — python
for account in await ads.ad_accounts(user_token):
    print(account.id, account.currency)

pixels

async

Lists the Meta pixels attached to the ad account, with last_fired_time. You need a pixel ID for conversion ad sets (promoted_object) and website audiences.

await ads.pixels(token: str, *, ad_account_id: str) -> list[dict]
  • Single page of up to 50 pixels; needs ads_read.

Required permissions:ads_read

Example — python
pixels = await ads.pixels(user_token, ad_account_id="act_123")

Targeting and estimates

Search targeting options, build a spec and estimate reach — no money spent.

build_targetingdelivery_estimatesearch_interestssearch_localessearch_locationssearch_targetingtargeting_suggestionsvalidate_targeting

build_targeting

staticmethod

Builds a Meta targeting spec (a dict) from plain arguments: locations, age, gender, locales, interests, behaviors, custom audiences and placements. A pure function: no network call and no token.

Ads.build_targeting(
    *,
    countries: Optional[list[str]] = None,
    regions: Optional[list[Any]] = None,
    cities: Optional[list[Any]] = None,
    zips: Optional[list[Any]] = None,
    excluded_countries: Optional[list[str]] = None,
    excluded_cities: Optional[list[Any]] = None,
    age_min: Optional[int] = None,
    age_max: Optional[int] = None,
    genders: Optional[list[Any]] = None,
    locales: Optional[list[int]] = None,
    interests: Optional[list[Any]] = None,
    behaviors: Optional[list[Any]] = None,
    demographics: Optional[list[Any]] = None,
    life_events: Optional[list[Any]] = None,
    excluded_interests: Optional[list[Any]] = None,
    custom_audiences: Optional[list[str]] = None,
    excluded_custom_audiences: Optional[list[str]] = None,
    platforms: Optional[list[str]] = None,
    facebook_positions: Optional[list[str]] = None,
    instagram_positions: Optional[list[str]] = None,
    devices: Optional[list[str]] = None,
    connections: Optional[list[str]] = None,
    excluded_connections: Optional[list[str]] = None,
    flexible_spec: Optional[list[dict]] = None,
    advantage_audience: bool = True,
) -> dict[str, Any]
  • Items inside interests are combined with OR; for AND, use flexible_spec, where each element is a separate AND condition.
  • genders accepts 1/2 or "male"/"female"; omit it to target everyone. Ages are clamped to 13–65.
  • advantage_audience defaults to True. With Advantage+ audience on, Meta fixes age_max at 65 and accepts age_min only from 18 to 25, so pass advantage_audience=False for hard age limits.
  • Meta requires a location in ad set targeting; this helper doesn't enforce it, so pass countries, regions, cities or zips.
Example — python
targeting = ads.build_targeting(countries=["UZ"], age_min=18, age_max=45, interests=[{"id": "6003107902433"}], advantage_audience=False)

Estimates audience size for a targeting spec and optimization goal without creating anything or spending money. Use it before creating an ad set to catch audiences that are too small or too broad.

await ads.delivery_estimate(
    token: str,
    *,
    ad_account_id: str,
    targeting: dict[str, Any],
    optimization_goal: str = 'REACH',
    promoted_object: Optional[dict] = None,
) -> dict
  • Read-only: nothing is created and nothing is billed.
  • Returns the first estimate row from Meta's response as a dict (an empty dict if there is none).
  • optimization_goal defaults to REACH; pass the goal you plan for the ad set.
  • Needs ads_read.

Required permissions:ads_read

Example — python
estimate = await ads.delivery_estimate(user_token, ad_account_id="act_123", targeting=targeting)

Searches Meta's interest targeting options by name and returns id, name, audience size bounds and path. Use the IDs in build_targeting(interests=...).

await ads.search_interests(token: str, query: str, *, limit: int = 25) -> list[dict]
  • limit defaults to 25; needs ads_read.
  • Meta deprecates interests over time, so check saved IDs with validate_targeting().

Required permissions:ads_read

Example — python
interests = await ads.search_interests(user_token, "fitness", limit=25)
cities = await ads.search_locations(user_token, "Tosh", country_code="UZ")

Searches Meta's locale (language) targeting options and returns numeric keys for build_targeting(locales=...). Use it when you split an audience by language rather than by location.

await ads.search_locales(token: str, query: str, *, limit: int = 25) -> list[dict]

Searches Meta locations (countries, regions, cities) by name; the key in the response is the identifier targeting expects. Narrow results with country_code.

await ads.search_locations(
    token: str,
    query: str,
    *,
    location_types: tuple[str, ...] = ('city', 'region', 'country'),
    country_code: Optional[str] = None,
    limit: int = 25,
) -> list[dict]
  • location_types defaults to city, region, country; add zip for postal codes.
  • A city can take a radius: {"key": "...", "radius": 25, "distance_unit": "kilometer"}; Meta accepts 17–80 km (10–50 miles).
  • Needs ads_read.

Required permissions:ads_read

Example — python
interests = await ads.search_interests(user_token, "fitness", limit=25)
cities = await ads.search_locations(user_token, "Tosh", country_code="UZ")

Lists or searches the targeting categories of one class, such as behaviors, demographics, life_events, industries or income. Without query it returns the whole class, for example to build a picker.

await ads.search_targeting(
    token: str,
    *,
    target_class: str = 'interests',
    query: Optional[str] = None,
    limit: int = 50,
) -> list[dict]
  • target_class must be one of TARGETING_CLASSES, otherwise ConfigurationError is raised before any request.

Suggests targeting options similar to the ones you pass, such as related interests. A quick way to widen an audience that came out too narrow.

await ads.targeting_suggestions(
    token: str,
    *,
    ad_account_id: str,
    targeting_list: list[dict],
    limit: int = 25,
) -> list[dict]
  • targeting_list format: [{"type": "interests", "id": "..."}]; needs ads_read.

Required permissions:ads_read

Example — python
similar = await ads.targeting_suggestions(user_token, ad_account_id="act_123", targeting_list=[{"type": "interests", "id": "6003107902433"}])

Checks whether saved targeting items (interest IDs and similar) are still valid for the ad account. Run it before reusing old targeting in a new ad set.

await ads.validate_targeting(
    token: str,
    *,
    ad_account_id: str,
    targeting_list: list[dict],
) -> list[dict]
  • Meta deprecates targeting options over time, so IDs saved months ago may stop working.
  • Needs ads_read.

Required permissions:ads_read

Example — python
result = await ads.validate_targeting(user_token, ad_account_id="act_123", targeting_list=[{"type": "interests", "id": "6003107902433"}])

Campaigns, ad sets and ads

Create and manage the three levels. By default everything is created PAUSED.

adsadsetadsetsboost_postcampaigncampaignscreate_adcreate_adsetcreate_campaigndeleteset_statusupdate_budgetupdate_targeting

ads

async

Lists ads with their creative, status and preview link, for one ad set, one campaign or the whole ad account.

await ads.ads(
    token: str,
    *,
    ad_account_id: Optional[str] = None,
    adset_id: Optional[str] = None,
    campaign_id: Optional[str] = None,
    limit: int = 100,
) -> list[dict]
  • Priority: adset_id, then campaign_id, then ad_account_id; with none, ConfigurationError.
  • One page of up to limit items; needs ads_read.

Required permissions:ads_read

Example — python
items = await ads.ads(user_token, adset_id="120200000000001")

adset

async

Fetches one ad set by ID with its targeting, budgets, bid, optimization goal and schedule.

await ads.adset(token: str, adset_id: str) -> dict

adsets

async

Lists the ad sets of a campaign (campaign_id) or of the whole ad account (ad_account_id), with targeting, budget and optimization fields.

await ads.adsets(
    token: str,
    *,
    ad_account_id: Optional[str] = None,
    campaign_id: Optional[str] = None,
    limit: int = 100,
) -> list[dict]
  • If both are given, campaign_id wins; with neither, ConfigurationError.
  • One page of up to limit (default 100) items; needs ads_read.

Required permissions:ads_read

Example — python
adsets = await ads.adsets(user_token, campaign_id="120200000000000")

Turns an existing Instagram post into an ad in one call: creates a campaign, an ad set, a creative from the post and the ad, all PAUSED. Returns their IDs; nothing spends until you call set_status(..., "ACTIVE").

await ads.boost_post(
    token: str,
    *,
    ad_account_id: str,
    ig_user_id: str,
    media_id: str,
    name: str,
    daily_budget_major: float,
    goal: str = 'traffic',
    page_id: Optional[str] = None,
    link: Optional[str] = None,
    targeting: Optional[dict[str, Any]] = None,
    currency: Optional[str] = None,
    cleanup_on_error: bool = True,
) -> dict[str, str]
  • goal: traffic, engagement, reach or messages (mapped to an OUTCOME_* objective and optimization goal); messages requires page_id. The campaign gets an empty special_ad_categories, so don't use it for housing, employment, financial or political ads.
  • daily_budget_major is in the account's currency and is multiplied by CURRENCY_OFFSET (100); for currencies Meta handles with offset 1 (JPY, KRW, IDR, VND, HUF, ...) divide by 100 first.
  • Without targeting it uses default_targeting(): UZ, ages 18–55, Instagram placements, Advantage+ audience on.
  • The four objects are created one after another: if a later step fails, the earlier ones stay in the account (PAUSED) and should be deleted. Posts with copyrighted music or interactive elements such as filters can't be boosted.

Required permissions:ads_managementinstagram_basic

Example — python
result = await ads.boost_post(user_token, ad_account_id="act_123", ig_user_id="1784...", media_id="1790...", name="Reels boost", daily_budget_major=10, goal="traffic")

Fetches one campaign by ID with the same fields as campaigns(): objective, status, budgets, bid strategy and special ad categories.

await ads.campaign(token: str, campaign_id: str) -> dict

Lists campaigns in an ad account with budget, objective and status fields. Filter with statuses, for example ["ACTIVE", "PAUSED"].

await ads.campaigns(
    token: str,
    *,
    ad_account_id: str,
    statuses: Optional[list[str]] = None,
    limit: int = 100,
) -> list[dict]
  • statuses is sent to Meta as the effective_status filter.
  • Returns one page of up to limit (default 100) items; there is no automatic paging.
  • Needs ads_read.

Required permissions:ads_read

Example — python
campaigns = await ads.campaigns(user_token, ad_account_id="act_123", statuses=["ACTIVE", "PAUSED"])

Creates an ad in an ad set from an existing creative_id or an inline creative spec. Created PAUSED by default.

await ads.create_ad(
    token: str,
    *,
    ad_account_id: str,
    name: str,
    adset_id: str,
    creative_id: Optional[str] = None,
    creative: Optional[dict] = None,
    status: str = 'PAUSED',
    **extra: Any,
) -> dict
  • Pass creative_id or creative; if both are given, creative_id is used.
  • Extra Meta fields go through **extra as strings or numbers (JSON-encode dicts yourself).

Required permissions:ads_management

Example — python
ad = await ads.create_ad(user_token, ad_account_id="act_123", name="Banner A", adset_id="120200000000001", creative_id="120200000000002")

Creates an ad set: who sees the ads (targeting), how delivery is optimized and, unless the campaign has a budget, how much it spends. Created PAUSED by default.

await ads.create_adset(
    token: str,
    *,
    ad_account_id: str,
    name: str,
    campaign_id: str,
    targeting: dict[str, Any],
    optimization_goal: str = 'LINK_CLICKS',
    billing_event: str = 'IMPRESSIONS',
    status: str = 'PAUSED',
    daily_budget_major: Optional[float] = None,
    lifetime_budget_major: Optional[float] = None,
    bid_amount_major: Optional[float] = None,
    start_time: Optional[str] = None,
    end_time: Optional[str] = None,
    promoted_object: Optional[dict] = None,
    destination_type: Optional[str] = None,
    currency: Optional[str] = None,
    **extra: Any,
) -> dict
  • targeting can't be empty; build it with build_targeting() or default_targeting(). optimization_goal and billing_event are checked against OPTIMIZATION_GOALS and BILLING_EVENTS.
  • daily_budget_major, lifetime_budget_major and bid_amount_major are multiplied by CURRENCY_OFFSET (100); for offset-1 currencies (JPY, KRW, IDR, VND, HUF, ...) divide by 100 first.
  • lifetime_budget_major requires end_time. At creation Meta accepts only ACTIVE or PAUSED status.
  • Some objectives need promoted_object, for example {"pixel_id": "...", "custom_event_type": "PURCHASE"} for conversions.

Required permissions:ads_management

Example — python
adset = await ads.create_adset(user_token, ad_account_id="act_123", name="Toshkent 18-45", campaign_id="120200000000000", targeting=targeting, daily_budget_major=15)

Creates a campaign, the top level that sets the objective and, optionally, a campaign budget. Created PAUSED by default.

await ads.create_campaign(
    token: str,
    *,
    ad_account_id: str,
    name: str,
    objective: str = 'OUTCOME_TRAFFIC',
    status: str = 'PAUSED',
    daily_budget_major: Optional[float] = None,
    lifetime_budget_major: Optional[float] = None,
    bid_strategy: Optional[str] = None,
    special_ad_categories: Optional[list[str]] = None,
    special_ad_category_country: Optional[list[str]] = None,
    is_adset_budget_sharing_enabled: Optional[bool] = None,
    currency: Optional[str] = None,
    **extra: Any,
) -> dict
  • objective must be one of the OUTCOME_* values in OBJECTIVES; legacy names raise ConfigurationError.
  • special_ad_categories is always sent (an empty list by default): Meta requires every campaign to declare its category, such as HOUSING, EMPLOYMENT, FINANCIAL_PRODUCTS_SERVICES or ISSUES_ELECTIONS_POLITICS.
  • Set the budget either here (daily_budget_major or lifetime_budget_major, one of them) or on the ad sets, not both. Amounts are multiplied by CURRENCY_OFFSET (100); for offset-1 currencies such as JPY or KRW, divide by 100 first.
  • From Marketing API v24.0, a campaign without its own budget needs is_adset_budget_sharing_enabled; pass it through **extra as a string ("false" or "true").

Required permissions:ads_management

Example — python
campaign = await ads.create_campaign(user_token, ad_account_id="act_123", name="Kuz aksiyasi", objective="OUTCOME_TRAFFIC", daily_budget_major=20)

delete

async

Deletes a campaign, ad set, ad or other Marketing API object by ID with an HTTP DELETE. To stop spending but keep the object, use set_status(..., "PAUSED") instead.

await ads.delete(token: str, node_id: str) -> bool
  • Returns Meta's success flag; needs ads_management.

Required permissions:ads_management

Example — python
await ads.delete(user_token, node_id)

Changes the status of a campaign, ad set or ad. ACTIVE starts spending; PAUSED stops delivery and is the safe way to turn ads off.

await ads.set_status(token: str, node_id: str, status: str) -> bool
  • Accepted values: ACTIVE, PAUSED, ARCHIVED, DELETED; anything else raises ConfigurationError.
  • While a campaign or ad set is paused, the effective status of its ads is CAMPAIGN_PAUSED or ADSET_PAUSED.
  • Needs ads_management.

Required permissions:ads_management

Example — python
await ads.set_status(user_token, campaign_id, "ACTIVE")

Sets a new daily budget on an ad set. It affects ads that are already running, so double-check the amount.

await ads.update_budget(
    token: str,
    adset_id: str,
    daily_budget_major: float,
    *,
    currency: Optional[str] = None,
    ad_account_id: Optional[str] = None,
) -> bool
  • daily_budget_major must be greater than 0 and is multiplied by CURRENCY_OFFSET (100); for offset-1 currencies divide by 100 first.
  • Needs ads_management.

Required permissions:ads_management

Example — python
await ads.update_budget(user_token, adset_id, daily_budget_major=25)

Replaces the targeting of an existing ad set with the spec you pass. Send the full new spec, not just the changes.

await ads.update_targeting(token: str, adset_id: str, targeting: dict[str, Any]) -> bool
  • An empty targeting raises ConfigurationError; needs ads_management.
  • Advantage+ audience age rules apply here too (see build_targeting()).

Required permissions:ads_management

Example — python
await ads.update_targeting(user_token, adset_id, targeting)

Creatives and images

What the ad looks like: image upload, creatives and previews.

create_creativepreviewupload_image

Creates a link ad creative from a Page, a URL, text and an uploaded image (image_hash) or video (video_id). Use it when the ad needs its own creative rather than an existing post (boost_post()).

await ads.create_creative(
    token: str,
    *,
    ad_account_id: str,
    name: str,
    page_id: str,
    link: str,
    message: Optional[str] = None,
    headline: Optional[str] = None,
    description: Optional[str] = None,
    image_hash: Optional[str] = None,
    video_id: Optional[str] = None,
    call_to_action: str = 'LEARN_MORE',
    instagram_user_id: Optional[str] = None,
    **extra: Any,
) -> dict
  • The SDK builds object_story_spec.link_data: headline goes to name, call_to_action (default LEARN_MORE) to type.
  • Pass instagram_user_id to run the ad under the Instagram account; page_id is always required.
  • Get image_hash from upload_image(). Needs ads_management.

Required permissions:ads_management

Example — python
creative = await ads.create_creative(user_token, ad_account_id="act_123", name="Kuz", page_id="1111", link="https://siz.uz", message="Chegirma 30%", image_hash=image_hash)

preview

async

Returns preview HTML (an iframe in body) showing how an ad looks in a given placement. Show it to a person before activating the ad.

await ads.preview(
    token: str,
    ad_id: str,
    *,
    ad_format: str = 'MOBILE_FEED_STANDARD',
) -> list[dict]
  • ad_format defaults to MOBILE_FEED_STANDARD; DESKTOP_FEED_STANDARD and other formats are listed in Meta's ad preview docs.
  • Needs ads_read.

Required permissions:ads_read

Example — python
previews = await ads.preview(user_token, ad_id, ad_format="INSTAGRAM_STANDARD")

Uploads image bytes to the ad account's image library and returns {"hash", "url", "raw"}. Creatives reference the image by this hash.

await ads.upload_image(
    token: str,
    *,
    ad_account_id: str,
    image: bytes,
    filename: str = 'ad.jpg',
) -> dict
  • image is raw bytes, not a path; filename only names the file in the upload.
  • Needs ads_management.

Required permissions:ads_management

Example — python
with open("banner.jpg", "rb") as f:
    image = await ads.upload_image(user_token, ad_account_id="act_123", image=f.read(), filename="banner.jpg")

Audiences

Custom, lookalike and saved audiences.

add_audience_userscreate_custom_audiencecreate_lookalikecustom_audiencessaved_audiences

Adds people to a customer-list audience by email and/or phone. Values are normalized and SHA-256-hashed on your server, so raw contact data never leaves it.

await ads.add_audience_users(
    token: str,
    audience_id: str,
    *,
    emails: Optional[list[str]] = None,
    phones: Optional[list[str]] = None,
    phone_country: Optional[str] = None,
    batch_size: int = 10000,
) -> dict
  • Normalization: emails are trimmed and lowercased; phones keep digits only. Leading zeros aren't removed and no country code is added, so pass numbers in international format such as +998901234567.
  • Meta accepts up to 10,000 records per request; split larger lists into several calls.
  • When you pass both lists, they are zipped row by row as the same person: keep them the same length and order (extra items are dropped).
  • Needs ads_management.

Required permissions:ads_management

Example — python
await ads.add_audience_users(user_token, audience_id, emails=["ali@example.com"], phones=["+998901234567"])

Creates an empty custom audience, by default a customer list (subtype="CUSTOM") that you then fill with add_audience_users().

await ads.create_custom_audience(
    token: str,
    *,
    ad_account_id: str,
    name: str,
    subtype: str = 'CUSTOM',
    description: Optional[str] = None,
    customer_file_source: str = 'USER_PROVIDED_ONLY',
    rule: Optional[dict] = None,
    **extra: Any,
) -> dict
  • For customer lists, the ad account must have accepted Meta's Custom Audience Terms; otherwise Meta returns a terms-not-accepted error.
  • customer_file_source declares where the data came from: USER_PROVIDED_ONLY (default), PARTNER_PROVIDED_ONLY or BOTH_USER_AND_PARTNER_PROVIDED.
  • rule is sent JSON-encoded; other Meta fields go through **extra. Needs ads_management.

Required permissions:ads_management

Example — python
audience = await ads.create_custom_audience(user_token, ad_account_id="act_123", name="Mijozlar")

Creates a lookalike audience in one country from a source audience. A smaller ratio means closer similarity and a smaller audience.

await ads.create_lookalike(
    token: str,
    *,
    ad_account_id: str,
    name: str,
    origin_audience_id: str,
    country: str = 'UZ',
    ratio: float = 0.01,
) -> dict
  • ratio ranges from 0.01 to 0.20 (the most similar 1–20% of the country); default 0.01, country defaults to UZ.
  • The source audience needs at least 100 people from a single country.
  • A lookalike takes 1–6 hours to populate; you can create ad sets that use it in the meantime.
  • Needs ads_management.

Required permissions:ads_management

Example — python
lookalike = await ads.create_lookalike(user_token, ad_account_id="act_123", name="1% UZ", origin_audience_id="1202...", country="UZ", ratio=0.01)

Lists custom audiences in the ad account with their subtype, approximate size bounds and delivery and operation status.

await ads.custom_audiences(
    token: str,
    *,
    ad_account_id: str,
    limit: int = 100,
) -> list[dict]
  • One page of up to limit (default 100) items; needs ads_read.

Required permissions:ads_read

Example — python
custom = await ads.custom_audiences(user_token, ad_account_id="act_123")
saved = await ads.saved_audiences(user_token, ad_account_id="act_123")

Lists saved audiences (targeting presets saved in Ads Manager) with their targeting spec and approximate size.

await ads.saved_audiences(
    token: str,
    *,
    ad_account_id: str,
    limit: int = 100,
) -> list[dict]
  • One page of up to limit items; needs ads_read.

Required permissions:ads_read

Example — python
custom = await ads.custom_audiences(user_token, ad_account_id="act_123")
saved = await ads.saved_audiences(user_token, ad_account_id="act_123")

Insights

Spend and results, as totals or by breakdown.

insightsinsights_rows

Returns spend and results for a campaign, ad set, ad or account as AdInsights (spend, impressions, reach, clicks, link_clicks, cpc, ctr, frequency). Use it for a quick totals card.

await ads.insights(
    token: str,
    node_id: str,
    *,
    since: Optional[str] = None,
    until: Optional[str] = None,
) -> socialift.ads.AdInsights
  • Give both since and until (YYYY-MM-DD); otherwise the whole lifetime (date_preset=maximum) is used.
  • Only the first row is read; for breakdowns use insights_rows().
  • Needs ads_read.

Returns raw insight rows at the chosen level with optional breakdowns such as age, gender, country or publisher_platform. Use it to find the segment where results are cheaper.

await ads.insights_rows(
    token: str,
    node_id: str,
    *,
    level: str = 'campaign',
    date_preset: Optional[str] = 'last_30d',
    since: Optional[str] = None,
    until: Optional[str] = None,
    breakdowns: Optional[list[str]] = None,
    action_breakdowns: Optional[list[str]] = None,
    fields: Optional[str] = None,
    limit: int = 200,
) -> list[dict]
  • Meta supports only some breakdown combinations: age + gender works, age + country does not.
  • since + until take precedence over date_preset (default last_30d).
  • One page of up to limit (default 200) rows; needs ads_read.

Required permissions:ads_read

Example — python
rows = await ads.insights_rows(user_token, "act_123", level="campaign", date_preset="last_7d", breakdowns=["age", "gender"])

Low-level calls

Direct access to Marketing API paths the SDK doesn't wrap.

call

call

async

Calls any Marketing API path with the SDK's signing (access_token, appsecret_proof), retries and error mapping. Use it for endpoints without a wrapper, such as automated rules.

await ads.call(token: str, path: str, *, method: str = 'GET', **params: Any) -> Any
  • Argument order is token, path; method defaults to GET. Anything other than GET/DELETE is sent as POST and changes real objects.
  • dict/list values are JSON-encoded for you; pass booleans as strings ("true"/"false").

Required permissions:ads_read

Example — python
data = await ads.call(user_token, "act_123/adcreatives", method="GET", fields="id,name")

Methods shared by all clients

Every HTTP client (Telegram, Facebook, Instagram, LinkedIn, TikTok, Ads) has these low-level methods — for calling an endpoint the SDK doesn't wrap yet or for reading pages of results. The connection is closed automatically when the async with block ends.

request

async

Sends an arbitrary HTTP request and returns the JSON response — for endpoints the SDK doesn't wrap with a dedicated method yet. You pass the token and signing parameters yourself in params or headers (access_token, and for Meta appsecret_proof via socialift.crypto.appsecret_proof).

await ads.request(
    method: str,
    url: str,
    *,
    params: Optional[Mapping[str, Any]] = None,
    data: Optional[Any] = None,
    json: Optional[Any] = None,
    headers: Optional[Mapping[str, str]] = None,
) -> Any
  • None values in params are not sent.
  • Rate limits (RateLimitError) and transient server errors (HTTP 429, 500, 502, 503, 504) are retried according to RetryPolicy; a Retry-After header is honoured. Network failures are raised as TransportError.

get

async

Shorthand for request("GET", ...).

await ads.get(url: str, **kw) -> Any

post

async

Shorthand for request("POST", ...).

await ads.post(url: str, **kw) -> Any

delete

async

Shorthand for request("DELETE", ...).

await ads.delete(url: str, **kw) -> Any

Follows Meta's cursor pagination (paging.next) and returns every data item as a single list.

await ads.paginate(
    url: str,
    *,
    params: Optional[Mapping[str, Any]] = None,
    max_items: int = 500,
    page_size: int = 100,
) -> list[dict]
  • max_items (default 500) is a safety cap — a large account can have tens of thousands of records. page_size sets the limit of each request.

close

async

Closes the HTTP session the SDK created itself (a session you passed in is left open). Called automatically when you use async with Client(...).

await ads.close() -> None

Frequently asked questions

Does creating a campaign through the SDK spend money?

Not by itself. create_campaign, create_adset and create_ad default to status="PAUSED", and boost_post() creates all four objects paused. While the campaign or ad set is paused, the ad's effective status is CAMPAIGN_PAUSED or ADSET_PAUSED, so set the campaign, ad set and ad to ACTIVE with set_status() when you are ready.

What currency are Meta ad budgets in?

The ad account's currency (AdAccount.currency). Arguments ending in _major are multiplied by CURRENCY_OFFSET (100) before sending. Meta uses offset 1 for some currencies (JPY, KRW, IDR, VND, HUF and others), so for those accounts divide by 100 first. UZS is not in Meta's list of ad account currencies.

Which permissions does the Meta Marketing API need?

A user access token with ads_read to read accounts, targeting and insights, and ads_management to create or change campaigns and audiences. boost_post() also lists instagram_basic. For production use, Meta requires App Review for these permissions.

How do I check audience size before launching Facebook ads?

Build the spec with build_targeting() and pass it to delivery_estimate(). It is read-only: nothing is created and nothing is billed. Use the same optimization_goal you plan for the ad set.

Is customer data sent to Meta in plain text when I upload an audience?

No. add_audience_users() normalizes emails and phone numbers and hashes them with SHA-256 on your server before the request. Meta accepts up to 10,000 records per request, so split larger lists across calls.

Sources

  1. Meta for Developers — Graph API and Marketing API versions
  2. Meta Marketing API — Currencies
  3. Meta Marketing API — Ad Set Budget Sharing
  4. Meta Marketing API — Advantage+ audience
  5. Meta Marketing API — Customer File Custom Audiences
  6. Meta Marketing API — Lookalike Audiences

Related pages