late-sdk 0.0.905 → 0.0.907
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +7 -0
- data/docs/AccountWithFollowerStats.md +2 -2
- data/docs/AdAccountsApi.md +1 -1
- data/docs/AdCampaignsApi.md +71 -1
- data/docs/AdCreative.md +4 -0
- data/docs/ConnectAds200ResponseOneOf.md +2 -0
- data/docs/ConnectApi.md +79 -5
- data/docs/CreateStandaloneAdRequest.md +8 -6
- data/docs/GooglePmaxAssetGroup.md +28 -0
- data/docs/GooglePmaxAssetGroupAssetsInner.md +28 -0
- data/docs/GooglePmaxAssetGroupInput.md +32 -0
- data/docs/GooglePmaxAssetGroupInputImages.md +22 -0
- data/docs/LeadGenApi.md +5 -5
- data/docs/ListAdAccounts200ResponseAccountsInner.md +4 -0
- data/docs/ListGoogleAssetGroups200Response.md +22 -0
- data/docs/SocialAccount.md +2 -2
- data/lib/zernio-sdk/api/ad_accounts_api.rb +2 -2
- data/lib/zernio-sdk/api/ad_campaigns_api.rb +70 -2
- data/lib/zernio-sdk/api/connect_api.rb +91 -6
- data/lib/zernio-sdk/api/lead_gen_api.rb +8 -8
- data/lib/zernio-sdk/models/account_with_follower_stats.rb +2 -2
- data/lib/zernio-sdk/models/ad_creative.rb +21 -1
- data/lib/zernio-sdk/models/connect_ads200_response_one_of.rb +45 -1
- data/lib/zernio-sdk/models/create_standalone_ad200_response_results_inner.rb +2 -2
- data/lib/zernio-sdk/models/create_standalone_ad_request.rb +18 -9
- data/lib/zernio-sdk/models/google_pmax_asset_group.rb +299 -0
- data/lib/zernio-sdk/models/google_pmax_asset_group_assets_inner.rb +244 -0
- data/lib/zernio-sdk/models/google_pmax_asset_group_input.rb +453 -0
- data/lib/zernio-sdk/models/google_pmax_asset_group_input_images.rb +280 -0
- data/lib/zernio-sdk/models/list_ad_accounts200_response_accounts_inner.rb +21 -1
- data/lib/zernio-sdk/models/list_google_asset_groups200_response.rb +204 -0
- data/lib/zernio-sdk/models/social_account.rb +2 -2
- data/lib/zernio-sdk/version.rb +1 -1
- data/lib/zernio-sdk.rb +5 -0
- data/openapi.yaml +277 -14
- data/spec/api/ad_accounts_api_spec.rb +1 -1
- data/spec/api/ad_campaigns_api_spec.rb +13 -1
- data/spec/api/connect_api_spec.rb +19 -3
- data/spec/api/lead_gen_api_spec.rb +4 -4
- data/spec/models/ad_creative_spec.rb +12 -0
- data/spec/models/connect_ads200_response_one_of_spec.rb +10 -0
- data/spec/models/create_standalone_ad200_response_results_inner_spec.rb +1 -1
- data/spec/models/create_standalone_ad_request_spec.rb +7 -1
- data/spec/models/google_pmax_asset_group_assets_inner_spec.rb +66 -0
- data/spec/models/google_pmax_asset_group_input_images_spec.rb +48 -0
- data/spec/models/google_pmax_asset_group_input_spec.rb +78 -0
- data/spec/models/google_pmax_asset_group_spec.rb +66 -0
- data/spec/models/list_ad_accounts200_response_accounts_inner_spec.rb +12 -0
- data/spec/models/list_google_asset_groups200_response_spec.rb +48 -0
- data/zernio-sdk-0.0.907.gem +0 -0
- metadata +22 -2
- data/zernio-sdk-0.0.905.gem +0 -0
data/openapi.yaml
CHANGED
|
@@ -7189,7 +7189,7 @@ components:
|
|
|
7189
7189
|
description: |
|
|
7190
7190
|
Reference to the parent posting SocialAccount. Set for ads accounts that share
|
|
7191
7191
|
or derive from a posting account's OAuth token. null for standalone ads (Google Ads)
|
|
7192
|
-
and all posting accounts.
|
|
7192
|
+
and all posting accounts. Meta ads business-login accounts also have no parent.
|
|
7193
7193
|
enabled:
|
|
7194
7194
|
type: boolean
|
|
7195
7195
|
description: |
|
|
@@ -7209,6 +7209,17 @@ components:
|
|
|
7209
7209
|
- wabaId: WhatsApp Business Account ID
|
|
7210
7210
|
- phoneNumberId: Meta phone number ID
|
|
7211
7211
|
|
|
7212
|
+
For Meta ads business-login accounts:
|
|
7213
|
+
- tokenType: system-user
|
|
7214
|
+
- businessId: The owning Business Manager ID when there is one owner; null for multiple owners.
|
|
7215
|
+
- businessIds: Owning Business Manager IDs discovered from granted ad accounts.
|
|
7216
|
+
- grantedAdAccountIds: Ad-account IDs granted to the token.
|
|
7217
|
+
- adAccountBusinesses: Map from ad-account ID to its owning business ID or null.
|
|
7218
|
+
- availablePages: Granted Page IDs and names. No Page tokens are exposed.
|
|
7219
|
+
- selectedPageId: The Page selected for creatives and lead forms, or null.
|
|
7220
|
+
- scopedAdAccountIds: Existing sync scope preserved on reconnect.
|
|
7221
|
+
Non-expiring tokens have no tokenExpiresAt field. Parent posting reconnects do not replace this token.
|
|
7222
|
+
|
|
7212
7223
|
For LinkedIn accounts, profileData carries the profile details refreshed on each daily snapshot:
|
|
7213
7224
|
- profileData.bio: The member's headline for personal accounts, or the organization description for organization accounts. null when the member has not set one.
|
|
7214
7225
|
- profileData.extraData.vanityName: The member's profile slug, i.e. the /in/{vanityName} segment of profileUrl. Personal accounts only; an organization's own slug is in metadata.organizationInfo.vanityName.
|
|
@@ -9312,6 +9323,88 @@ components:
|
|
|
9312
9323
|
$ref: '#/components/schemas/GoogleStructuredSnippet'
|
|
9313
9324
|
description: "Supply fields for exactly one asset type per update. finalUrls may accompany sitelinkAsset. Shared asset edits affect every attachment using the asset."
|
|
9314
9325
|
|
|
9326
|
+
GooglePmaxAssetGroupInput:
|
|
9327
|
+
type: object
|
|
9328
|
+
additionalProperties: false
|
|
9329
|
+
required: [finalUrl, headlines, longHeadline, descriptions, businessName, images]
|
|
9330
|
+
description: "Google Performance Max creative assets. At least one description must be 60 characters or fewer. Texts within each list must be distinct."
|
|
9331
|
+
properties:
|
|
9332
|
+
name: { type: string, minLength: 1, maxLength: 128, description: "Defaults to the request name." }
|
|
9333
|
+
finalUrl: { type: string, format: uri, pattern: '^https?://', description: "Required destination URL." }
|
|
9334
|
+
headlines:
|
|
9335
|
+
type: array
|
|
9336
|
+
minItems: 3
|
|
9337
|
+
maxItems: 15
|
|
9338
|
+
uniqueItems: true
|
|
9339
|
+
items: { type: string, minLength: 1, maxLength: 30 }
|
|
9340
|
+
longHeadline: { type: string, minLength: 1, maxLength: 90 }
|
|
9341
|
+
descriptions:
|
|
9342
|
+
type: array
|
|
9343
|
+
minItems: 2
|
|
9344
|
+
maxItems: 5
|
|
9345
|
+
uniqueItems: true
|
|
9346
|
+
description: "At least one description must be 60 characters or fewer."
|
|
9347
|
+
items: { type: string, minLength: 1, maxLength: 90 }
|
|
9348
|
+
businessName: { type: string, minLength: 1, maxLength: 25 }
|
|
9349
|
+
images:
|
|
9350
|
+
type: object
|
|
9351
|
+
additionalProperties: false
|
|
9352
|
+
required: [landscape, square, logo]
|
|
9353
|
+
description: "Public HTTP(S) image URLs. GIF, JPEG or PNG, at most 5120 KB per image. Google validates dimensions and aspect ratios."
|
|
9354
|
+
properties:
|
|
9355
|
+
landscape:
|
|
9356
|
+
type: array
|
|
9357
|
+
minItems: 1
|
|
9358
|
+
maxItems: 20
|
|
9359
|
+
description: "Landscape marketing images. Aspect ratio 1.91:1, minimum 600 x 314 pixels."
|
|
9360
|
+
items: { type: string, format: uri, pattern: '^https?://' }
|
|
9361
|
+
square:
|
|
9362
|
+
type: array
|
|
9363
|
+
minItems: 1
|
|
9364
|
+
maxItems: 20
|
|
9365
|
+
description: "Square marketing images. Aspect ratio 1:1, minimum 300 x 300 pixels."
|
|
9366
|
+
items: { type: string, format: uri, pattern: '^https?://' }
|
|
9367
|
+
logo:
|
|
9368
|
+
type: array
|
|
9369
|
+
minItems: 1
|
|
9370
|
+
maxItems: 5
|
|
9371
|
+
description: "Required square logos. Aspect ratio 1:1, minimum 128 x 128 pixels."
|
|
9372
|
+
items: { type: string, format: uri, pattern: '^https?://' }
|
|
9373
|
+
youtubeVideoId:
|
|
9374
|
+
type: string
|
|
9375
|
+
pattern: '^[A-Za-z0-9_-]{11}$'
|
|
9376
|
+
description: "Optional existing YouTube video id. Google can generate video when omitted. Video uploads and arbitrary video URLs are not supported."
|
|
9377
|
+
example:
|
|
9378
|
+
finalUrl: 'https://zernio.com'
|
|
9379
|
+
headlines: ['Schedule posts', 'One social API', 'Build with Zernio']
|
|
9380
|
+
longHeadline: 'Schedule social content from your app with Zernio'
|
|
9381
|
+
descriptions: ['Connect your social accounts.', 'Publish and manage social content through one API.']
|
|
9382
|
+
businessName: Zernio
|
|
9383
|
+
images:
|
|
9384
|
+
landscape: ['https://example.com/landscape.png']
|
|
9385
|
+
square: ['https://example.com/square.png']
|
|
9386
|
+
logo: ['https://example.com/logo.png']
|
|
9387
|
+
GooglePmaxAssetGroup:
|
|
9388
|
+
type: object
|
|
9389
|
+
required: [id, resourceName, name, status, finalUrls, assets]
|
|
9390
|
+
properties:
|
|
9391
|
+
id: { type: string }
|
|
9392
|
+
resourceName: { type: string }
|
|
9393
|
+
name: { type: string }
|
|
9394
|
+
status: { type: string, description: "Asset-group status on Google. Campaign status independently controls delivery." }
|
|
9395
|
+
finalUrls: { type: array, items: { type: string, format: uri } }
|
|
9396
|
+
assets:
|
|
9397
|
+
type: array
|
|
9398
|
+
items:
|
|
9399
|
+
type: object
|
|
9400
|
+
required: [resourceName, fieldType, status]
|
|
9401
|
+
properties:
|
|
9402
|
+
resourceName: { type: string }
|
|
9403
|
+
fieldType: { type: string, description: "Google asset role, such as HEADLINE or LOGO." }
|
|
9404
|
+
status: { type: string }
|
|
9405
|
+
text: { type: string }
|
|
9406
|
+
imageUrl: { type: string, format: uri }
|
|
9407
|
+
youtubeVideoId: { type: string }
|
|
9315
9408
|
GoogleRsaHeadline:
|
|
9316
9409
|
type: object
|
|
9317
9410
|
required:
|
|
@@ -9500,6 +9593,13 @@ components:
|
|
|
9500
9593
|
type: [object, "null"]
|
|
9501
9594
|
description: Platform-specific creative data. Fields vary by platform.
|
|
9502
9595
|
properties:
|
|
9596
|
+
assetGroup:
|
|
9597
|
+
$ref: '#/components/schemas/GooglePmaxAssetGroupInput'
|
|
9598
|
+
description: "Initial Performance Max asset group input. Use the asset-groups endpoint for current Google assets."
|
|
9599
|
+
assetGroupResourceName:
|
|
9600
|
+
type: string
|
|
9601
|
+
description: "Google resource name of the created Performance Max asset group."
|
|
9602
|
+
example: "customers/9122445560/assetGroups/123456789"
|
|
9503
9603
|
headlines:
|
|
9504
9604
|
type: array
|
|
9505
9605
|
minItems: 3
|
|
@@ -19402,10 +19502,31 @@ paths:
|
|
|
19402
19502
|
x-resource-group: "accounts"
|
|
19403
19503
|
operationId: connectAds
|
|
19404
19504
|
tags: [Connect]
|
|
19505
|
+
x-platforms: [meta, linkedin, tiktok, twitter, pinterest, google]
|
|
19405
19506
|
summary: Connect ads for a platform
|
|
19406
19507
|
description: |
|
|
19407
19508
|
Unified ads connection endpoint. Creates a dedicated ads SocialAccount for the specified platform.
|
|
19408
19509
|
|
|
19510
|
+
**Meta business login (opt-in).** Set `loginMode=business` for `facebook` or
|
|
19511
|
+
`instagram` to use Facebook Login for Business and a Business Integration System User
|
|
19512
|
+
token. No posting account is created or required. This mode always returns an authUrl;
|
|
19513
|
+
it returns 503 when the server has no META_ADS_CONFIG_ID. Complete the dialog in a
|
|
19514
|
+
browser. The callback creates or reconnects only the metaads account, preserving its
|
|
19515
|
+
ID, history and scopedAdAccountIds. Non-empty successful subscription results replace
|
|
19516
|
+
subscribedAdAccountIds to remove stale grants; an empty result leaves routing unchanged. A reconnect must grant
|
|
19517
|
+
every previously scoped ad account (or every previous grant for an unscoped connection).
|
|
19518
|
+
Missing or unverifiable grants return 409 before changing the account.
|
|
19519
|
+
|
|
19520
|
+
Pass `pageId` to select a granted Page for creatives and lead forms. Otherwise the
|
|
19521
|
+
previous Page or sole granted Page is selected. Multiple Pages without a selection
|
|
19522
|
+
return 400 with available Page IDs; restart with pageId. With no Pages granted the
|
|
19523
|
+
account can manage campaigns and sync insights but cannot create Page-based creatives
|
|
19524
|
+
or list Page forms. Success redirects with connected=metaads, profileId and accountId.
|
|
19525
|
+
Business login reports metadata.tokenType=system-user in GET /v1/accounts. An absent
|
|
19526
|
+
Meta expires_in leaves tokenExpiresAt absent; no personal-token re-exchange occurs.
|
|
19527
|
+
Subsequent classic requests can change the ad-account scope using the business token;
|
|
19528
|
+
force=true requires loginMode=business to reconnect that connection.
|
|
19529
|
+
|
|
19409
19530
|
**Same-token platforms (facebook, instagram, linkedin, pinterest).** The ads SocialAccount
|
|
19410
19531
|
(metaads, linkedinads, pinterestads) reuses the OAuth token of the parent posting account,
|
|
19411
19532
|
but only when an active parent exists and, for facebook and instagram, its stored token
|
|
@@ -19438,6 +19559,16 @@ paths:
|
|
|
19438
19559
|
|
|
19439
19560
|
Ads accounts appear as regular SocialAccount documents with ads platform values (e.g., metaads, tiktokads) in GET /v1/accounts.
|
|
19440
19561
|
parameters:
|
|
19562
|
+
- name: loginMode
|
|
19563
|
+
in: query
|
|
19564
|
+
schema: { type: string, enum: [classic, business], default: classic }
|
|
19565
|
+
description: "Meta ads authorization mode. Business login is opt-in for Facebook and Instagram; classic preserves the posting-account flow."
|
|
19566
|
+
example: business
|
|
19567
|
+
- name: pageId
|
|
19568
|
+
in: query
|
|
19569
|
+
schema: { type: string, pattern: '^\d+$' }
|
|
19570
|
+
description: "Business login only. Facebook Page ID to select from the token grants for ad creatives and lead forms."
|
|
19571
|
+
example: "811889972008357"
|
|
19441
19572
|
- name: platform
|
|
19442
19573
|
in: path
|
|
19443
19574
|
required: true
|
|
@@ -19447,7 +19578,7 @@ paths:
|
|
|
19447
19578
|
description: |
|
|
19448
19579
|
Platform to connect ads for. Only platforms with ads support are accepted.
|
|
19449
19580
|
|
|
19450
|
-
`instagram` requires an Instagram account connected with loginMethod=facebook_login whose
|
|
19581
|
+
In classic mode, `instagram` requires an Instagram account connected with loginMethod=facebook_login whose
|
|
19451
19582
|
token carries ads_management and ads_read. With an account connected through the default
|
|
19452
19583
|
instagram_login flow no ads account can be created; do not use this value for those accounts.
|
|
19453
19584
|
- name: profileId
|
|
@@ -19501,7 +19632,9 @@ paths:
|
|
|
19501
19632
|
schema: { type: string }
|
|
19502
19633
|
description: |
|
|
19503
19634
|
Scope ad sync to a single platform ad account. Without this param,
|
|
19504
|
-
sync covers every ad account the connected token can see.
|
|
19635
|
+
sync covers every ad account the connected token can see. Business-login reconnects
|
|
19636
|
+
preserve the existing scope; supplied IDs are checked against the new grant. To change
|
|
19637
|
+
that scope after migration, call this endpoint with the IDs and omit loginMode. Supported
|
|
19505
19638
|
on `facebook`/`instagram` (Meta, `act_<digits>`), `linkedin` (bare
|
|
19506
19639
|
numeric sponsored-account id), `googleads` (bare customer id digits)
|
|
19507
19640
|
and `twitter` (X Ads, base36 account id). `tiktok` scopes advertisers
|
|
@@ -19543,6 +19676,7 @@ paths:
|
|
|
19543
19676
|
platform: { type: string }
|
|
19544
19677
|
username: { type: string }
|
|
19545
19678
|
displayName: { type: string }
|
|
19679
|
+
tokenType: { type: string, enum: [system-user], description: "Present for an existing business-login connection." }
|
|
19546
19680
|
scopedAdAccountIds:
|
|
19547
19681
|
type: array
|
|
19548
19682
|
items: { type: string }
|
|
@@ -19564,6 +19698,11 @@ paths:
|
|
|
19564
19698
|
platform: "instagram"
|
|
19565
19699
|
username: "@mybrand"
|
|
19566
19700
|
displayName: "My Brand"
|
|
19701
|
+
businessLogin:
|
|
19702
|
+
summary: Meta ads business login
|
|
19703
|
+
value:
|
|
19704
|
+
authUrl: "https://www.facebook.com/v24.0/dialog/oauth?client_id=APP_ID&config_id=CONFIG_ID&response_type=code&override_default_response_type=true&redirect_uri=https%3A%2F%2Fzernio.com%2Fapi%2Fv1%2Fconnect%2Fmeta-ads%2Fcallback&state=ENCRYPTED_STATE"
|
|
19705
|
+
state: "ENCRYPTED_STATE"
|
|
19567
19706
|
oauthRequired:
|
|
19568
19707
|
summary: Separate-token platform (TikTok) needing ads OAuth
|
|
19569
19708
|
value:
|
|
@@ -19576,6 +19715,35 @@ paths:
|
|
|
19576
19715
|
description: "Ads access required (Ads add-on on legacy plans, included on usage-based plans), or no access to profile"
|
|
19577
19716
|
'404':
|
|
19578
19717
|
description: "Profile or posting account not found"
|
|
19718
|
+
'409':
|
|
19719
|
+
description: "Reconnect a system-user connection with loginMode=business."
|
|
19720
|
+
'503':
|
|
19721
|
+
description: "Business login is not configured or the platform is temporarily unavailable."
|
|
19722
|
+
|
|
19723
|
+
/v1/connect/meta-ads/callback:
|
|
19724
|
+
get:
|
|
19725
|
+
operationId: completeMetaAdsBusinessLogin
|
|
19726
|
+
summary: Complete Meta business login
|
|
19727
|
+
tags: [Connect]
|
|
19728
|
+
x-platforms: [meta]
|
|
19729
|
+
x-resource-group: "accounts"
|
|
19730
|
+
security: []
|
|
19731
|
+
description: "Facebook Login for Business redirect target. Meta supplies the single-use authorization code and the authenticated state returned by connectAds. The state expires after 30 minutes and binds the user, profile, Page selection and ad-account scope. No bearer token is sent by the browser. Success reconnects only metaads and redirects to the original redirect_url. Invalid state returns 400; inaccessible profiles or missing ads access cannot connect. No token is returned to the browser."
|
|
19732
|
+
parameters:
|
|
19733
|
+
- { name: state, in: query, required: true, schema: { type: string }, description: "Authenticated state from the initial connectAds response.", example: "ENCRYPTED_STATE" }
|
|
19734
|
+
- { name: code, in: query, schema: { type: string }, description: "Single-use authorization code returned by Meta." }
|
|
19735
|
+
- { name: error, in: query, schema: { type: string }, description: "Meta authorization error when the user declines the dialog." }
|
|
19736
|
+
responses:
|
|
19737
|
+
'307':
|
|
19738
|
+
description: "Redirect to the original callback URL with connected=metaads, profileId and accountId on success; authorization denial redirects with an error."
|
|
19739
|
+
headers:
|
|
19740
|
+
Location:
|
|
19741
|
+
schema: { type: string, format: uri }
|
|
19742
|
+
example: "https://example.com/callback?connected=metaads&profileId=PROFILE_ID&accountId=ACCOUNT_ID"
|
|
19743
|
+
'400': { $ref: '#/components/responses/BadRequest' }
|
|
19744
|
+
'403': { description: "Ads access or profile access required." }
|
|
19745
|
+
'409': { description: "The new token grants do not match the existing connection, or its previous grants cannot be verified." }
|
|
19746
|
+
'503': { description: "Business login state signing is not configured." }
|
|
19579
19747
|
|
|
19580
19748
|
/v1/connect/shopify:
|
|
19581
19749
|
get:
|
|
@@ -49698,6 +49866,9 @@ paths:
|
|
|
49698
49866
|
description: |
|
|
49699
49867
|
Returns the platform ad accounts available for the given account (e.g. Meta ad
|
|
49700
49868
|
accounts, TikTok advertiser IDs, Google Ads customer IDs).
|
|
49869
|
+
Meta business-login accounts use their own system-user token. Fresh Meta discovery
|
|
49870
|
+
includes businessId and businessName from the owning Business Manager when available;
|
|
49871
|
+
cached entries gain these fields after the next discovery refresh.
|
|
49701
49872
|
|
|
49702
49873
|
For TikTok agencies: enumerates every advertiser under every Business Center the token
|
|
49703
49874
|
can read (paginated server-side), then chunks the lookup against TikTok's
|
|
@@ -49729,6 +49900,8 @@ paths:
|
|
|
49729
49900
|
id: { type: string, description: "Platform ad account ID (e.g. act_123)" }
|
|
49730
49901
|
name: { type: string }
|
|
49731
49902
|
currency: { type: string }
|
|
49903
|
+
businessId: { type: string, description: "Meta only. Owning Business Manager ID when available on the grant." }
|
|
49904
|
+
businessName: { type: string, description: "Owning business name when supplied by the platform." }
|
|
49732
49905
|
status: { type: string, description: "LinkedIn only. LinkedIn's own ad account status. In practice always `ACTIVE`, because the LinkedIn query filters to active accounts. Meta, Google, TikTok and Pinterest report `accountStatus` instead; X reports `approvalStatus`." }
|
|
49733
49906
|
accountStatus:
|
|
49734
49907
|
description: |
|
|
@@ -50258,6 +50431,55 @@ paths:
|
|
|
50258
50431
|
Also returned as `idempotency_key_reused` when an Idempotency-Key
|
|
50259
50432
|
is reused with a different request body.
|
|
50260
50433
|
|
|
50434
|
+
/v1/ads/campaigns/{campaignId}/asset-groups:
|
|
50435
|
+
get:
|
|
50436
|
+
operationId: listGoogleAssetGroups
|
|
50437
|
+
summary: List Performance Max asset groups
|
|
50438
|
+
tags: ["Ad Campaigns"]
|
|
50439
|
+
x-platforms: ["google"]
|
|
50440
|
+
x-resource-group: "ads"
|
|
50441
|
+
description: "Read Performance Max asset groups and their linked text, image and YouTube assets. campaignId is the platform campaign id returned by creation or the campaign list. The campaign must be visible to the caller. Uses a 10-minute cache, with the last successful response served as stale when Google quota is exhausted. Removed groups and asset links are excluded. Campaign-level brand assets on campaigns with brand guidelines enabled are not included."
|
|
50442
|
+
security:
|
|
50443
|
+
- bearerAuth: []
|
|
50444
|
+
parameters:
|
|
50445
|
+
- name: campaignId
|
|
50446
|
+
in: path
|
|
50447
|
+
required: true
|
|
50448
|
+
schema: { type: string, pattern: '^\d+$' }
|
|
50449
|
+
description: "Google Ads campaign id."
|
|
50450
|
+
responses:
|
|
50451
|
+
'200':
|
|
50452
|
+
description: "Asset groups and linked assets."
|
|
50453
|
+
content:
|
|
50454
|
+
application/json:
|
|
50455
|
+
schema:
|
|
50456
|
+
type: object
|
|
50457
|
+
required: [assetGroups, cachedAt, stale]
|
|
50458
|
+
properties:
|
|
50459
|
+
assetGroups: { type: array, items: { $ref: '#/components/schemas/GooglePmaxAssetGroup' } }
|
|
50460
|
+
cachedAt: { type: [string, "null"], format: date-time }
|
|
50461
|
+
stale: { type: boolean }
|
|
50462
|
+
example:
|
|
50463
|
+
assetGroups:
|
|
50464
|
+
- id: '123456789'
|
|
50465
|
+
resourceName: 'customers/9122445560/assetGroups/123456789'
|
|
50466
|
+
name: 'Social publishing'
|
|
50467
|
+
status: ENABLED
|
|
50468
|
+
finalUrls: ['https://zernio.com']
|
|
50469
|
+
assets:
|
|
50470
|
+
- resourceName: 'customers/9122445560/assets/987654321'
|
|
50471
|
+
fieldType: HEADLINE
|
|
50472
|
+
status: ENABLED
|
|
50473
|
+
text: 'Schedule posts'
|
|
50474
|
+
cachedAt: '2026-09-10T09:00:00Z'
|
|
50475
|
+
stale: false
|
|
50476
|
+
'400': { $ref: '#/components/responses/BadRequest' }
|
|
50477
|
+
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
50478
|
+
'404': { $ref: '#/components/responses/NotFound' }
|
|
50479
|
+
'429':
|
|
50480
|
+
description: "Google quota or operation budget exhausted with no cached response."
|
|
50481
|
+
'501':
|
|
50482
|
+
description: "Campaign is not on Google Ads."
|
|
50261
50483
|
/v1/ads/create:
|
|
50262
50484
|
post:
|
|
50263
50485
|
x-resource-group: "ads"
|
|
@@ -50268,7 +50490,20 @@ paths:
|
|
|
50268
50490
|
description: |
|
|
50269
50491
|
Create a paid ad with custom creative across Meta, Google Ads, Pinterest, TikTok, X, LinkedIn, and OpenAI Ads (ChatGPT Ads).
|
|
50270
50492
|
|
|
50271
|
-
|
|
50493
|
+
Google Performance Max: set `campaignType: "pmax"` and supply `assetGroup` with
|
|
50494
|
+
text, images by role, business name and finalUrl. Creates a daily budget, PAUSED
|
|
50495
|
+
campaign and asset group atomically. `validateOnly: true` validates the complete
|
|
50496
|
+
request with Google without creating or persisting resources. Read assets with
|
|
50497
|
+
`GET /v1/ads/campaigns/{campaignId}/asset-groups`. The logo is required; video is
|
|
50498
|
+
optional via `assetGroup.youtubeVideoId`. Brand guidelines are disabled at creation.
|
|
50499
|
+
PMax rejects ACTIVE creation, portfolio bidding, bid caps, legacy creative fields
|
|
50500
|
+
and attach shapes. Geo and language targeting are supported; omitted geo targets
|
|
50501
|
+
all locations. PMax does not require top-level goal, headline, body or linkUrl.
|
|
50502
|
+
Supported bidding: omitted or LOWEST_COST_WITHOUT_CAP for Maximize Conversions,
|
|
50503
|
+
COST_CAP plus bidAmount for target CPA, LOWEST_COST_WITH_MIN_ROAS plus
|
|
50504
|
+
roasAverageFloor for Maximize Conversion Value with target ROAS.
|
|
50505
|
+
|
|
50506
|
+
Other mutually-exclusive request shapes are selected by the body:
|
|
50272
50507
|
|
|
50273
50508
|
- Legacy single-creative shape (all platforms, the default).
|
|
50274
50509
|
- Meta-only multi-creative shape via the creatives array: one ad set with N ads sharing budget and targeting.
|
|
@@ -50347,13 +50582,13 @@ paths:
|
|
|
50347
50582
|
description: "Meta only. Multi-advertiser ads: whether Meta may show this ad alongside other advertisers' in one unit. Meta auto-enrols since Aug 2024, so send OPT_OUT to leave. It is a top-level creative field, NOT a `creativeFeatures` key, and Meta rejects it there."
|
|
50348
50583
|
validateOnly:
|
|
50349
50584
|
type: boolean
|
|
50350
|
-
description: '
|
|
50351
|
-
budgetAmount: { type: number, description: "Budget in WHOLE currency units (USD: 50 = $50.00), NOT cents. Meta's own Marketing API takes this same number in minor units, so it is an easy and expensive mix-up. Required on legacy
|
|
50352
|
-
budgetType: { type: string, enum: [daily, lifetime], description: "Required on legacy
|
|
50585
|
+
description: 'Google Performance Max validates the complete atomic campaign and asset group with no resource creation or local persistence. Google validation still downloads image URLs and consumes quota. On Meta, validates the complete inline campaign, ad set, creative and ad with execution_options validate_only. Nothing is uploaded or created, and validation bypasses Idempotency-Key storage. Supports a single image, existing video.id or existingCreativeId; media pools, new video uploads, creatives[], adSetId and RESERVED buying return 400. Existing campaign or creative nodes are marked skipped. Success returns 200 with per-node results; Meta rejection returns an error.'
|
|
50586
|
+
budgetAmount: { type: number, description: "Budget in WHOLE currency units (USD: 50 = $50.00), NOT cents. Meta's own Marketing API takes this same number in minor units, so it is an easy and expensive mix-up. Required on legacy, multi-creative and Performance Max shapes. Inherited on attach. OpenAI Ads requires a $1 minimum (its budget is lifetime-only, see budgetType)." }
|
|
50587
|
+
budgetType: { type: string, enum: [daily, lifetime], description: "Required on legacy, multi-creative and Performance Max shapes. Inherited on attach. OpenAI Ads accepts lifetime only (no daily-budget concept on the platform); sending daily returns 422. OpenAI Ads lifetime budgets require `endDate` to give the lifetime cap a spend window." }
|
|
50353
50588
|
status:
|
|
50354
50589
|
type: string
|
|
50355
50590
|
enum: [ACTIVE, PAUSED]
|
|
50356
|
-
description: "Meta, TikTok, and LinkedIn
|
|
50591
|
+
description: "Google Performance Max accepts PAUSED only and always creates a paused campaign. Meta, TikTok, and LinkedIn: publish state of the created entities. Omitted or ACTIVE publishes live (default, back-compat); PAUSED creates them paused so you can review before they spend. On Meta the pause is held on the campaign this call creates, leaving the ad set and ad switched on, so a single PUT /v1/ads/campaigns/{campaignId}/status with `active` brings the whole thing live. It is held at every level instead when the pause cannot rely on the campaign: `existingCampaignId` (that campaign may be running and is never touched) or `campaignStatus: ACTIVE`. On TikTok the whole campaign > ad group > ad hierarchy stays paused. On LinkedIn the whole campaign group, campaign, and creative hierarchy stays PAUSED (intendedStatus PAUSED on each)."
|
|
50357
50592
|
campaignStatus:
|
|
50358
50593
|
type: string
|
|
50359
50594
|
enum: [ACTIVE, PAUSED]
|
|
@@ -50984,7 +51219,9 @@ paths:
|
|
|
50984
51219
|
type: array
|
|
50985
51220
|
items: { type: string, enum: [mobile, desktop] }
|
|
50986
51221
|
audienceId: { type: string, description: Custom audience ID for targeting }
|
|
50987
|
-
campaignType: { type: string, enum: [display, search], default: display, description: Google only }
|
|
51222
|
+
campaignType: { type: string, enum: [display, search, pmax], default: display, description: "Google only. Performance Max requires assetGroup and is always created PAUSED." }
|
|
51223
|
+
assetGroup:
|
|
51224
|
+
$ref: '#/components/schemas/GooglePmaxAssetGroupInput'
|
|
50988
51225
|
keywords: { type: array, maxItems: 1000, items: { $ref: '#/components/schemas/KeywordEntry' }, description: "Google Search only. Keywords on the new ad group; entries are strings (BROAD) or { text, matchType }. Editable later via PUT /v1/ads/{adId} targeting.keywords." }
|
|
50989
51226
|
negativeKeywords: { type: array, maxItems: 1000, items: { $ref: '#/components/schemas/KeywordEntry' }, description: "Google Search only; other platforms return 400. Ad-group-level negative keywords on the new ad group. Editable later via PUT /v1/ads/{adId} targeting.negativeKeywords." }
|
|
50990
51227
|
campaignNegativeKeywords: { type: array, maxItems: 1000, items: { $ref: '#/components/schemas/KeywordEntry' }, description: "Google Search only; other platforms return 400. Campaign-level negative keywords (campaign_criterion.negative), created alongside the ad group. Editable later via PUT /v1/ads/campaigns/{campaignId}/negative-keywords." }
|
|
@@ -51126,7 +51363,7 @@ paths:
|
|
|
51126
51363
|
portfolioBidStrategyId:
|
|
51127
51364
|
type: string
|
|
51128
51365
|
pattern: '^\d+$'
|
|
51129
|
-
description: "Google only. Attach an existing portfolio bid strategy (numeric id from GET /v1/ads/bid-strategies) to the new campaign instead of a standard one. Exclusive with bidStrategy."
|
|
51366
|
+
description: "Google Search and Display only. Performance Max rejects portfolio bidding. Attach an existing portfolio bid strategy (numeric id from GET /v1/ads/bid-strategies) to the new campaign instead of a standard one. Exclusive with bidStrategy."
|
|
51130
51367
|
valueRuleSetId:
|
|
51131
51368
|
type: string
|
|
51132
51369
|
pattern: '^\d+$'
|
|
@@ -51264,6 +51501,29 @@ paths:
|
|
|
51264
51501
|
promotedObject:
|
|
51265
51502
|
$ref: '#/components/schemas/AdPromotedObject'
|
|
51266
51503
|
examples:
|
|
51504
|
+
performanceMax:
|
|
51505
|
+
summary: "Paused Performance Max campaign."
|
|
51506
|
+
value:
|
|
51507
|
+
accountId: '69ce75d483e990e1c01ccfe4'
|
|
51508
|
+
adAccountId: '9122445560'
|
|
51509
|
+
name: 'Social publishing'
|
|
51510
|
+
campaignType: pmax
|
|
51511
|
+
budgetAmount: 1
|
|
51512
|
+
budgetType: daily
|
|
51513
|
+
status: PAUSED
|
|
51514
|
+
validateOnly: true
|
|
51515
|
+
countries: [US]
|
|
51516
|
+
languages: [en]
|
|
51517
|
+
assetGroup:
|
|
51518
|
+
finalUrl: 'https://zernio.com'
|
|
51519
|
+
headlines: ['Schedule posts', 'One social API', 'Build with Zernio']
|
|
51520
|
+
longHeadline: 'Schedule social content from your app with Zernio'
|
|
51521
|
+
descriptions: ['Connect your social accounts.', 'Publish and manage social content through one API.']
|
|
51522
|
+
businessName: Zernio
|
|
51523
|
+
images:
|
|
51524
|
+
landscape: ['https://example.com/landscape.png']
|
|
51525
|
+
square: ['https://example.com/square.png']
|
|
51526
|
+
logo: ['https://example.com/logo.png']
|
|
51267
51527
|
appPromotion:
|
|
51268
51528
|
value:
|
|
51269
51529
|
accountId: '69fc524892b3d8e85f893e73'
|
|
@@ -51322,7 +51582,7 @@ paths:
|
|
|
51322
51582
|
items:
|
|
51323
51583
|
type: object
|
|
51324
51584
|
properties:
|
|
51325
|
-
node: { type: string, enum: [campaign, adSet, creative, ad] }
|
|
51585
|
+
node: { type: string, enum: [campaign, adSet, creative, ad, performanceMaxCampaign] }
|
|
51326
51586
|
status: { type: string, enum: [validated, skipped] }
|
|
51327
51587
|
reason: { type: string, description: "Why the node could not be validated (only on skipped)." }
|
|
51328
51588
|
message: { type: string }
|
|
@@ -51436,11 +51696,11 @@ paths:
|
|
|
51436
51696
|
summary: List lead forms
|
|
51437
51697
|
description: >
|
|
51438
51698
|
Lists the Lead Gen forms owned by the account. Meta: forms on the
|
|
51439
|
-
connected Facebook Page. LinkedIn: forms owned by the ad account's
|
|
51699
|
+
connected Facebook Page, including a Page selected on a metaads business-login connection. LinkedIn: forms owned by the ad account's
|
|
51440
51700
|
Company Page. Pass `adAccountId` (LinkedIn forms are org-owned).
|
|
51441
51701
|
Requires the Ads add-on.
|
|
51442
51702
|
parameters:
|
|
51443
|
-
- { name: accountId, in: query, required: true, schema: { type: string }, description: Connected
|
|
51703
|
+
- { name: accountId, in: query, required: true, schema: { type: string }, description: "Connected Facebook, Meta ads business-login or LinkedIn ads account ID." }
|
|
51444
51704
|
- { name: adAccountId, in: query, schema: { type: string }, description: "LinkedIn only: the LinkedIn ad account id (used to resolve the owning organization). Required for LinkedIn." }
|
|
51445
51705
|
- { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 100, default: 25 } }
|
|
51446
51706
|
- { name: cursor, in: query, schema: { type: string } }
|
|
@@ -51467,7 +51727,8 @@ paths:
|
|
|
51467
51727
|
description: >
|
|
51468
51728
|
Creates a Lead Gen form. The form content goes inside
|
|
51469
51729
|
`platformSpecificData` for both platforms (the shape is selected by the
|
|
51470
|
-
accountId's platform). Meta: created on the connected Facebook Page
|
|
51730
|
+
accountId's platform). Meta: created on the connected Facebook Page (a
|
|
51731
|
+
facebook account or a metaads business-login account with a selected Page)
|
|
51471
51732
|
(POST /{page-id}/leadgen_forms); the old top-level Meta fields
|
|
51472
51733
|
(questions, thankYou*, contextCard, …) are DEPRECATED but still
|
|
51473
51734
|
accepted while platformSpecificData is absent; mixing both shapes is
|
|
@@ -51661,6 +51922,8 @@ paths:
|
|
|
51661
51922
|
description: >
|
|
51662
51923
|
Returns leads for one form. Serves persisted leads (ingested via the
|
|
51663
51924
|
leadgen webhook) when available, falling back to a live Graph read.
|
|
51925
|
+
Accepts a Facebook account or a metaads business-login account with leads_retrieval
|
|
51926
|
+
access to the form; the latter uses its system-user token without a posting parent.
|
|
51664
51927
|
parameters:
|
|
51665
51928
|
- { name: formId, in: path, required: true, schema: { type: string } }
|
|
51666
51929
|
- { name: accountId, in: query, required: true, schema: { type: string } }
|
|
@@ -345,7 +345,7 @@ describe 'AdAccountsApi' do
|
|
|
345
345
|
|
|
346
346
|
# unit tests for list_ad_accounts
|
|
347
347
|
# List ad accounts
|
|
348
|
-
# Returns the platform ad accounts available for the given account (e.g. Meta ad accounts, TikTok advertiser IDs, Google Ads customer IDs). For TikTok agencies: enumerates every advertiser under every Business Center the token can read (paginated server-side), then chunks the lookup against TikTok's `/advertiser/info/` endpoint (which has a per-call cap of ≤100 IDs). Solo advertisers without a BC fall back to the OAuth-time `advertiser_ids` list. Cached for 1h on the SocialAccount; lazy-refreshed on first call after expiry. For Google Ads: responds `429` when Google's API quota is temporarily exhausted (instead of an empty list). Retry after a delay.
|
|
348
|
+
# Returns the platform ad accounts available for the given account (e.g. Meta ad accounts, TikTok advertiser IDs, Google Ads customer IDs). Meta business-login accounts use their own system-user token. Fresh Meta discovery includes businessId and businessName from the owning Business Manager when available; cached entries gain these fields after the next discovery refresh. For TikTok agencies: enumerates every advertiser under every Business Center the token can read (paginated server-side), then chunks the lookup against TikTok's `/advertiser/info/` endpoint (which has a per-call cap of ≤100 IDs). Solo advertisers without a BC fall back to the OAuth-time `advertiser_ids` list. Cached for 1h on the SocialAccount; lazy-refreshed on first call after expiry. For Google Ads: responds `429` when Google's API quota is temporarily exhausted (instead of an empty list). Retry after a delay.
|
|
349
349
|
# @param account_id Account ID
|
|
350
350
|
# @param [Hash] opts the optional parameters
|
|
351
351
|
# @option opts [String] :ad_account_id Filter response to a single platform ad account ID (e.g. `act_123` for Meta, advertiser_id for TikTok). Returns at most one item.
|
|
@@ -135,7 +135,7 @@ describe 'AdCampaignsApi' do
|
|
|
135
135
|
|
|
136
136
|
# unit tests for create_standalone_ad
|
|
137
137
|
# Create standalone ad
|
|
138
|
-
# Create a paid ad with custom creative across Meta, Google Ads, Pinterest, TikTok, X, LinkedIn, and OpenAI Ads (ChatGPT Ads).
|
|
138
|
+
# Create a paid ad with custom creative across Meta, Google Ads, Pinterest, TikTok, X, LinkedIn, and OpenAI Ads (ChatGPT Ads). Google Performance Max: set `campaignType: \"pmax\"` and supply `assetGroup` with text, images by role, business name and finalUrl. Creates a daily budget, PAUSED campaign and asset group atomically. `validateOnly: true` validates the complete request with Google without creating or persisting resources. Read assets with `GET /v1/ads/campaigns/{campaignId}/asset-groups`. The logo is required; video is optional via `assetGroup.youtubeVideoId`. Brand guidelines are disabled at creation. PMax rejects ACTIVE creation, portfolio bidding, bid caps, legacy creative fields and attach shapes. Geo and language targeting are supported; omitted geo targets all locations. PMax does not require top-level goal, headline, body or linkUrl. Supported bidding: omitted or LOWEST_COST_WITHOUT_CAP for Maximize Conversions, COST_CAP plus bidAmount for target CPA, LOWEST_COST_WITH_MIN_ROAS plus roasAverageFloor for Maximize Conversion Value with target ROAS. Other mutually-exclusive request shapes are selected by the body: - Legacy single-creative shape (all platforms, the default). - Meta-only multi-creative shape via the creatives array: one ad set with N ads sharing budget and targeting. - Attach shape via adSetId: adds one new ad to an existing ad set, inheriting its budget, targeting, and schedule (Meta, Google Ads, TikTok, and LinkedIn). On LinkedIn adSetId is the existing Campaign id, and the budget, schedule, targeting and bidding fields must be omitted. Meta accepts `promotion` and `creativeFeatures` on the single and attach shapes and as defaults for `creatives[]`. An item replaces the whole feature map; its `promotion` replaces the default offer, and `promotion: null` disables that default for the item. Reusing `existingCreativeId` uses the existing creative settings instead of new settings. Requested settings are persisted for lists, exports, and default ad-detail reads. Only ads supplied a `promotion` receive live readback; multi-create batches those reads in groups of up to 50 IDs without per-ad fallback. Inspect `ad.creative.promotionStatus` (or `ads[].creative.promotionStatus`). `not_returned` means Meta omitted the metadata; successful creation does not by itself prove the offer was applied or will display. Per-platform required fields, budget minimums, and video-ad rules are documented on each property below. LinkedIn creates a Single Image or Single Video Ad backed by a Direct Sponsored Content \"dark post\" authored by a Company Page (see `organizationId`). Supported goals are engagement, traffic, awareness, and video_views (video ads use the `video` field; video_views requires a video), and traffic ads require `linkUrl`. **Idempotency:** this endpoint is not idempotent at the platform level (a blind retry creates a second campaign/ad set/ad). Send an `Idempotency-Key` header to make retries safe: the first request with a given key creates the ad and we store the response; a retry with the same key replays that exact response (with `Idempotent-Replayed: true`) instead of creating duplicates. Reusing a key with a different body returns 422; a key whose first request is still in flight returns 409 (retry after a short backoff). Keys are scoped to your credential and expire after 24h.
|
|
139
139
|
# @param create_standalone_ad_request
|
|
140
140
|
# @param [Hash] opts the optional parameters
|
|
141
141
|
# @option opts [String] :idempotency_key Optional client-generated unique key (e.g. a UUID) that makes retries safe. Same key + same body replays the original response; same key + different body → 422; key still processing → 409.
|
|
@@ -481,6 +481,18 @@ describe 'AdCampaignsApi' do
|
|
|
481
481
|
end
|
|
482
482
|
end
|
|
483
483
|
|
|
484
|
+
# unit tests for list_google_asset_groups
|
|
485
|
+
# List Performance Max asset groups
|
|
486
|
+
# Read Performance Max asset groups and their linked text, image and YouTube assets. campaignId is the platform campaign id returned by creation or the campaign list. The campaign must be visible to the caller. Uses a 10-minute cache, with the last successful response served as stale when Google quota is exhausted. Removed groups and asset links are excluded. Campaign-level brand assets on campaigns with brand guidelines enabled are not included.
|
|
487
|
+
# @param campaign_id Google Ads campaign id.
|
|
488
|
+
# @param [Hash] opts the optional parameters
|
|
489
|
+
# @return [ListGoogleAssetGroups200Response]
|
|
490
|
+
describe 'list_google_asset_groups test' do
|
|
491
|
+
it 'should work' do
|
|
492
|
+
# assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
|
|
493
|
+
end
|
|
494
|
+
end
|
|
495
|
+
|
|
484
496
|
# unit tests for remove_ad_group_assets
|
|
485
497
|
# Remove ad-group assets
|
|
486
498
|
# Removes the specified attachments only. Google assets cannot be deleted. Other attachments remain. assetResourceNames is retained for compatibility.
|
|
@@ -45,6 +45,20 @@ describe 'ConnectApi' do
|
|
|
45
45
|
end
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
+
# unit tests for complete_meta_ads_business_login
|
|
49
|
+
# Complete Meta business login
|
|
50
|
+
# Facebook Login for Business redirect target. Meta supplies the single-use authorization code and the authenticated state returned by connectAds. The state expires after 30 minutes and binds the user, profile, Page selection and ad-account scope. No bearer token is sent by the browser. Success reconnects only metaads and redirects to the original redirect_url. Invalid state returns 400; inaccessible profiles or missing ads access cannot connect. No token is returned to the browser.
|
|
51
|
+
# @param state Authenticated state from the initial connectAds response.
|
|
52
|
+
# @param [Hash] opts the optional parameters
|
|
53
|
+
# @option opts [String] :code Single-use authorization code returned by Meta.
|
|
54
|
+
# @option opts [String] :error Meta authorization error when the user declines the dialog.
|
|
55
|
+
# @return [nil]
|
|
56
|
+
describe 'complete_meta_ads_business_login test' do
|
|
57
|
+
it 'should work' do
|
|
58
|
+
# assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
48
62
|
# unit tests for complete_telegram_connect
|
|
49
63
|
# Check Telegram status
|
|
50
64
|
# Poll this endpoint to check if a Telegram access code has been used to connect a channel/group. Recommended polling interval: 3 seconds. Status values: pending (waiting for user), connected (channel/group linked), expired (generate a new code).
|
|
@@ -84,15 +98,17 @@ describe 'ConnectApi' do
|
|
|
84
98
|
|
|
85
99
|
# unit tests for connect_ads
|
|
86
100
|
# Connect ads for a platform
|
|
87
|
-
# Unified ads connection endpoint. Creates a dedicated ads SocialAccount for the specified platform. **Same-token platforms (facebook, instagram, linkedin, pinterest).** The ads SocialAccount (metaads, linkedinads, pinterestads) reuses the OAuth token of the parent posting account, but only when an active parent exists and, for facebook and instagram, its stored token carries ads_management and ads_read (linkedin and pinterest need no extra scope). In that case no extra OAuth happens and the response is alreadyConnected: true. When no such parent exists, or the scopes are missing, the endpoint returns an authUrl and a full OAuth round trip is required. When a parent exists but carries no token usable for ad accounts, the call fails with 400 RECONNECT_REQUIRED. Independently of the branch, the call can return 403 ADS_ADDON_REQUIRED without the ads add-on and 402 PAYMENT_REQUIRED when the billing gate is closed. Meta Ads prerequisite: connecting Meta Ads (via facebook or instagram) requires a Facebook Page. Not because the ad account is read through a Page, but because both parent posting accounts are: the facebook flow only offers Pages you manage, and the instagram flow with loginMethod=facebook_login only offers Instagram accounts linked to one of those Pages. Without a Page there is no parent account to inherit a token from. A user who manages no Facebook Page cannot complete this connection, and the facebook flow ends with error=no_facebook_pages. **Separate-token platforms (tiktok, twitter).** Starts the platform-specific marketing API OAuth flow and creates an ads SocialAccount (tiktokads, xads) with its own token. If the ads account already exists, returns alreadyConnected: true. - tiktok: accountId is OPTIONAL. With accountId, the new tiktokads account links to that posting account (parentAccountId set), so Spark Ads + standalone ads using the posting TT_USER identity become available. Without accountId, ads-only mode kicks in: the new tiktokads account has parentAccountId=null and standalone ads use a synthetic CUSTOMIZED_USER (\"Brand Identity\"); Spark Ads are unavailable because TikTok requires a posting account for them. The Brand Identity is configured separately via PATCH /v1/connect/tiktok-ads (or inline on POST /v1/ads/create via the brandIdentity field). - twitter (X Ads): accountId is REQUIRED. There's no ads-only mode, because tweets need to be authored by a real X user. **Standalone platforms (googleads).** Starts the Google Ads OAuth flow and creates a standalone ads SocialAccount (googleads) with no parent. If the account already exists, returns alreadyConnected: true. Ads accounts appear as regular SocialAccount documents with ads platform values (e.g., metaads, tiktokads) in GET /v1/accounts.
|
|
88
|
-
# @param platform Platform to connect ads for. Only platforms with ads support are accepted. `instagram` requires an Instagram account connected with loginMethod=facebook_login whose token carries ads_management and ads_read. With an account connected through the default instagram_login flow no ads account can be created; do not use this value for those accounts.
|
|
101
|
+
# Unified ads connection endpoint. Creates a dedicated ads SocialAccount for the specified platform. **Meta business login (opt-in).** Set `loginMode=business` for `facebook` or `instagram` to use Facebook Login for Business and a Business Integration System User token. No posting account is created or required. This mode always returns an authUrl; it returns 503 when the server has no META_ADS_CONFIG_ID. Complete the dialog in a browser. The callback creates or reconnects only the metaads account, preserving its ID, history and scopedAdAccountIds. Non-empty successful subscription results replace subscribedAdAccountIds to remove stale grants; an empty result leaves routing unchanged. A reconnect must grant every previously scoped ad account (or every previous grant for an unscoped connection). Missing or unverifiable grants return 409 before changing the account. Pass `pageId` to select a granted Page for creatives and lead forms. Otherwise the previous Page or sole granted Page is selected. Multiple Pages without a selection return 400 with available Page IDs; restart with pageId. With no Pages granted the account can manage campaigns and sync insights but cannot create Page-based creatives or list Page forms. Success redirects with connected=metaads, profileId and accountId. Business login reports metadata.tokenType=system-user in GET /v1/accounts. An absent Meta expires_in leaves tokenExpiresAt absent; no personal-token re-exchange occurs. Subsequent classic requests can change the ad-account scope using the business token; force=true requires loginMode=business to reconnect that connection. **Same-token platforms (facebook, instagram, linkedin, pinterest).** The ads SocialAccount (metaads, linkedinads, pinterestads) reuses the OAuth token of the parent posting account, but only when an active parent exists and, for facebook and instagram, its stored token carries ads_management and ads_read (linkedin and pinterest need no extra scope). In that case no extra OAuth happens and the response is alreadyConnected: true. When no such parent exists, or the scopes are missing, the endpoint returns an authUrl and a full OAuth round trip is required. When a parent exists but carries no token usable for ad accounts, the call fails with 400 RECONNECT_REQUIRED. Independently of the branch, the call can return 403 ADS_ADDON_REQUIRED without the ads add-on and 402 PAYMENT_REQUIRED when the billing gate is closed. Meta Ads prerequisite: connecting Meta Ads (via facebook or instagram) requires a Facebook Page. Not because the ad account is read through a Page, but because both parent posting accounts are: the facebook flow only offers Pages you manage, and the instagram flow with loginMethod=facebook_login only offers Instagram accounts linked to one of those Pages. Without a Page there is no parent account to inherit a token from. A user who manages no Facebook Page cannot complete this connection, and the facebook flow ends with error=no_facebook_pages. **Separate-token platforms (tiktok, twitter).** Starts the platform-specific marketing API OAuth flow and creates an ads SocialAccount (tiktokads, xads) with its own token. If the ads account already exists, returns alreadyConnected: true. - tiktok: accountId is OPTIONAL. With accountId, the new tiktokads account links to that posting account (parentAccountId set), so Spark Ads + standalone ads using the posting TT_USER identity become available. Without accountId, ads-only mode kicks in: the new tiktokads account has parentAccountId=null and standalone ads use a synthetic CUSTOMIZED_USER (\"Brand Identity\"); Spark Ads are unavailable because TikTok requires a posting account for them. The Brand Identity is configured separately via PATCH /v1/connect/tiktok-ads (or inline on POST /v1/ads/create via the brandIdentity field). - twitter (X Ads): accountId is REQUIRED. There's no ads-only mode, because tweets need to be authored by a real X user. **Standalone platforms (googleads).** Starts the Google Ads OAuth flow and creates a standalone ads SocialAccount (googleads) with no parent. If the account already exists, returns alreadyConnected: true. Ads accounts appear as regular SocialAccount documents with ads platform values (e.g., metaads, tiktokads) in GET /v1/accounts.
|
|
102
|
+
# @param platform Platform to connect ads for. Only platforms with ads support are accepted. In classic mode, `instagram` requires an Instagram account connected with loginMethod=facebook_login whose token carries ads_management and ads_read. With an account connected through the default instagram_login flow no ads account can be created; do not use this value for those accounts.
|
|
89
103
|
# @param profile_id Your Zernio profile ID
|
|
90
104
|
# @param [Hash] opts the optional parameters
|
|
105
|
+
# @option opts [String] :login_mode Meta ads authorization mode. Business login is opt-in for Facebook and Instagram; classic preserves the posting-account flow.
|
|
106
|
+
# @option opts [String] :page_id Business login only. Facebook Page ID to select from the token grants for ad creatives and lead forms.
|
|
91
107
|
# @option opts [String] :account_id Existing SocialAccount ID. Required for `twitter` (X Ads). Optional for `tiktok`: omit to enter ads-only mode (no TikTok posting account linked; ad creation uses a Brand Identity instead of a TT_USER). Ignored for same-token (`facebook`, `instagram`, `linkedin`, `pinterest`) and standalone (`googleads`) platforms.
|
|
92
108
|
# @option opts [String] :redirect_url Custom URL the browser is sent to once the OAuth flow finishes. Honored on every ads platform, including the separate-token (`tiktok`, `twitter`) and standalone (`googleads`) flows. MUST be an absolute http(s) URL or a custom app scheme for mobile deeplinks (e.g. myapp://callback); a relative path is rejected with 400 INVALID_REDIRECT_URL. On success `tiktok`, `twitter` and `googleads` land on the URL unchanged, while the same-token platforms (`facebook`, `instagram`, `linkedin`, `pinterest`) append `connected`, `profileId`, `accountId`, `username` and, on API-key calls, `connect_token`. On failure the same error contract applies as on GET /v1/connect/{platform}: `error` and `platform` are always appended, other params are optional, and the value list there is not exhaustive. On the tiktok, twitter and googleads flows `platform` carries the ads platform id (`tiktokads`, `xads`, `googleads`), not the value used in the request path. When omitted, the browser lands on the Zernio dashboard.
|
|
93
109
|
# @option opts [Boolean] :headless Enable headless mode (same-token platforms only)
|
|
94
110
|
# @option opts [Boolean] :force Force a fresh OAuth even when an account already exists. Normally the endpoint returns `alreadyConnected: true` whenever a connected account is found, keying off its active state rather than token liveness. Set `force=true` to bypass that and always receivean `authUrl`. Completing the returned OAuth refreshes the stored token on the existing posting and ads accounts in place.
|
|
95
|
-
# @option opts [String] :ad_account_id Scope ad sync to a single platform ad account. Without this param, sync covers every ad account the connected token can see. Supported on `facebook`/`instagram` (Meta, `act_<digits>`), `linkedin` (bare numeric sponsored-account id), `googleads` (bare customer id digits) and `twitter` (X Ads, base36 account id). `tiktok` scopes advertisers at OAuth and `pinterest` has no ads discovery, so both ignore it. Meta ids are additionally validated against the connected token; unreachable IDs return 400. Setting a scope also removes already synced ads from de-scoped ad accounts. For multiple accounts use `adAccountIds` instead.
|
|
111
|
+
# @option opts [String] :ad_account_id Scope ad sync to a single platform ad account. Without this param, sync covers every ad account the connected token can see. Business-login reconnects preserve the existing scope; supplied IDs are checked against the new grant. To change that scope after migration, call this endpoint with the IDs and omit loginMode. Supported on `facebook`/`instagram` (Meta, `act_<digits>`), `linkedin` (bare numeric sponsored-account id), `googleads` (bare customer id digits) and `twitter` (X Ads, base36 account id). `tiktok` scopes advertisers at OAuth and `pinterest` has no ads discovery, so both ignore it. Meta ids are additionally validated against the connected token; unreachable IDs return 400. Setting a scope also removes already synced ads from de-scoped ad accounts. For multiple accounts use `adAccountIds` instead.
|
|
96
112
|
# @option opts [Array<String>] :ad_account_ids Scope ad sync to multiple platform ad accounts (same platform support and id shapes as `adAccountId`). Repeat the param (`?adAccountIds=act_1&adAccountIds=act_2`) or comma-separate (`?adAccountIds=act_1,act_2`). Persisted server-side; latest call wins, and de-scoped ad accounts have their synced ads removed. Omitting both `adAccountId` and `adAccountIds` keeps any previously persisted scope unchanged.
|
|
97
113
|
# @return [ConnectAds200Response]
|
|
98
114
|
describe 'connect_ads test' do
|
|
@@ -47,7 +47,7 @@ describe 'LeadGenApi' do
|
|
|
47
47
|
|
|
48
48
|
# unit tests for create_lead_form
|
|
49
49
|
# Create a lead form
|
|
50
|
-
# Creates a Lead Gen form. The form content goes inside `platformSpecificData` for both platforms (the shape is selected by the accountId's platform). Meta: created on the connected Facebook Page (POST /{page-id}/leadgen_forms); the old top-level Meta fields (questions, thankYou*, contextCard, …) are DEPRECATED but still accepted while platformSpecificData is absent; mixing both shapes is a 400. LinkedIn: created on the ad account's Company Page. NOT idempotent: a retry creates a second form. Meta prefilled question types (EMAIL, PHONE, FULL_NAME, …) must omit label/key; CUSTOM questions require both. LinkedIn exposes only free-text and multiple-choice questions via API (prefilled-from-profile fields are Campaign Manager UI-only). Requires the Ads add-on.
|
|
50
|
+
# Creates a Lead Gen form. The form content goes inside `platformSpecificData` for both platforms (the shape is selected by the accountId's platform). Meta: created on the connected Facebook Page (a facebook account or a metaads business-login account with a selected Page) (POST /{page-id}/leadgen_forms); the old top-level Meta fields (questions, thankYou*, contextCard, …) are DEPRECATED but still accepted while platformSpecificData is absent; mixing both shapes is a 400. LinkedIn: created on the ad account's Company Page. NOT idempotent: a retry creates a second form. Meta prefilled question types (EMAIL, PHONE, FULL_NAME, …) must omit label/key; CUSTOM questions require both. LinkedIn exposes only free-text and multiple-choice questions via API (prefilled-from-profile fields are Campaign Manager UI-only). Requires the Ads add-on.
|
|
51
51
|
# @param create_lead_form_request
|
|
52
52
|
# @param [Hash] opts the optional parameters
|
|
53
53
|
# @return [CreateLeadForm200Response]
|
|
@@ -84,7 +84,7 @@ describe 'LeadGenApi' do
|
|
|
84
84
|
|
|
85
85
|
# unit tests for list_form_leads
|
|
86
86
|
# List leads for a single form
|
|
87
|
-
# Returns leads for one form. Serves persisted leads (ingested via the leadgen webhook) when available, falling back to a live Graph read.
|
|
87
|
+
# Returns leads for one form. Serves persisted leads (ingested via the leadgen webhook) when available, falling back to a live Graph read. Accepts a Facebook account or a metaads business-login account with leads_retrieval access to the form; the latter uses its system-user token without a posting parent.
|
|
88
88
|
# @param form_id
|
|
89
89
|
# @param account_id
|
|
90
90
|
# @param [Hash] opts the optional parameters
|
|
@@ -100,8 +100,8 @@ describe 'LeadGenApi' do
|
|
|
100
100
|
|
|
101
101
|
# unit tests for list_lead_forms
|
|
102
102
|
# List lead forms
|
|
103
|
-
# Lists the Lead Gen forms owned by the account. Meta: forms on the connected Facebook Page. LinkedIn: forms owned by the ad account's Company Page. Pass `adAccountId` (LinkedIn forms are org-owned). Requires the Ads add-on.
|
|
104
|
-
# @param account_id Connected
|
|
103
|
+
# Lists the Lead Gen forms owned by the account. Meta: forms on the connected Facebook Page, including a Page selected on a metaads business-login connection. LinkedIn: forms owned by the ad account's Company Page. Pass `adAccountId` (LinkedIn forms are org-owned). Requires the Ads add-on.
|
|
104
|
+
# @param account_id Connected Facebook, Meta ads business-login or LinkedIn ads account ID.
|
|
105
105
|
# @param [Hash] opts the optional parameters
|
|
106
106
|
# @option opts [String] :ad_account_id LinkedIn only: the LinkedIn ad account id (used to resolve the owning organization). Required for LinkedIn.
|
|
107
107
|
# @option opts [Integer] :limit
|