@zernio/node 0.2.1169 → 0.2.1170
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.
- package/dist/index.d.mts +200 -103
- package/dist/index.d.ts +200 -103
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
- package/src/generated/sdk.gen.ts +127 -16
- package/src/generated/types.gen.ts +200 -103
package/dist/index.js
CHANGED
|
@@ -36,7 +36,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
36
36
|
// package.json
|
|
37
37
|
var package_default = {
|
|
38
38
|
name: "@zernio/node",
|
|
39
|
-
version: "0.2.
|
|
39
|
+
version: "0.2.1170",
|
|
40
40
|
description: "The official Node.js library for the Zernio API",
|
|
41
41
|
main: "dist/index.js",
|
|
42
42
|
module: "dist/index.mjs",
|
package/dist/index.mjs
CHANGED
|
@@ -5,7 +5,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
5
5
|
// package.json
|
|
6
6
|
var package_default = {
|
|
7
7
|
name: "@zernio/node",
|
|
8
|
-
version: "0.2.
|
|
8
|
+
version: "0.2.1170",
|
|
9
9
|
description: "The official Node.js library for the Zernio API",
|
|
10
10
|
main: "dist/index.js",
|
|
11
11
|
module: "dist/index.mjs",
|
package/package.json
CHANGED
package/src/generated/sdk.gen.ts
CHANGED
|
@@ -1474,6 +1474,13 @@ export const verifyWhatsAppNumber = <ThrowOnError extends boolean = false>(optio
|
|
|
1474
1474
|
* inbound message webhook does not reach Zernio, `platformConnection.inboundWebhookSubscribed`
|
|
1475
1475
|
* is `false`, an entry is added to `issues`, and the overall `status` is at least `warning`.
|
|
1476
1476
|
*
|
|
1477
|
+
* For the standalone ads connections (`googleads`, `redditads`) a connection that cannot serve
|
|
1478
|
+
* requests until a fresh OAuth repairs it adds an entry to `issues` and a recommendation to call
|
|
1479
|
+
* `GET /v1/connect/{platform}/ads`, whose `authUrl` reconnects the same account. On `redditads`
|
|
1480
|
+
* this is a connection authorized before Zernio needed a Reddit permission it now uses (for
|
|
1481
|
+
* example `adsconversions`): Reddit refuses those requests until the user reconnects and allows
|
|
1482
|
+
* every permission on Reddit's consent screen.
|
|
1483
|
+
*
|
|
1477
1484
|
*/
|
|
1478
1485
|
export const getAccountHealth = <ThrowOnError extends boolean = false>(options: OptionsLegacyParser<GetAccountHealthData, ThrowOnError>) => {
|
|
1479
1486
|
return (options?.client ?? client).get<GetAccountHealthResponse, GetAccountHealthError, ThrowOnError>({
|
|
@@ -1824,6 +1831,22 @@ export const handleOAuthCallback = <ThrowOnError extends boolean = false>(option
|
|
|
1824
1831
|
* whose token lacks that permission is flagged needsReconnection, and the health endpoints
|
|
1825
1832
|
* report "Google Ads permission not granted"; this endpoint then returns an authUrl for it.
|
|
1826
1833
|
*
|
|
1834
|
+
* **Standalone platforms (redditads).** Starts the Reddit Ads OAuth flow (Reddit permissions
|
|
1835
|
+
* `adsread`, `adsedit` and `adsconversions`) and creates a standalone ads SocialAccount
|
|
1836
|
+
* (redditads) with no parent, separate from any organic `reddit` posting account. It is
|
|
1837
|
+
* reached only as `redditads` in the path. If an active Reddit Ads connection already exists
|
|
1838
|
+
* on the profile, is not flagged needsReconnection and holds every one of those permissions,
|
|
1839
|
+
* returns alreadyConnected: true. Otherwise it returns an authUrl; completing it reconnects
|
|
1840
|
+
* the same account (same accountId). A connection authorized without `adsconversions` keeps
|
|
1841
|
+
* managing ads, but the health endpoints list an issue asking to reconnect Reddit Ads and
|
|
1842
|
+
* allow every permission, the Conversions API answers 403 `reconnect_required`, and this
|
|
1843
|
+
* endpoint returns an authUrl for it. Discovery lists every Reddit ad account the Reddit user
|
|
1844
|
+
* can reach. When the user unticks `adsread` or `adsedit` on Reddit's consent screen the
|
|
1845
|
+
* callback saves nothing and redirects with `error=reddit_ads_scope_not_granted`; when the
|
|
1846
|
+
* user reaches no Reddit ad account it redirects with `error=reddit_ads_no_ad_accounts`
|
|
1847
|
+
* (both with `platform=redditads`). Without `redirect_url` the browser lands on the Zernio
|
|
1848
|
+
* dashboard's ad account picker for the new connection.
|
|
1849
|
+
*
|
|
1827
1850
|
* Ads accounts appear as regular SocialAccount documents with ads platform values (e.g., metaads, tiktokads) in GET /v1/accounts.
|
|
1828
1851
|
*
|
|
1829
1852
|
*/
|
|
@@ -9801,7 +9824,7 @@ export const removeAdKeyword = <ThrowOnError extends boolean = false>(options: O
|
|
|
9801
9824
|
* which reads the switches from the platform now, stores them, and returns `statusReadAt`
|
|
9802
9825
|
* (null when the read failed and the stored values were returned).
|
|
9803
9826
|
* With `live=true` (which needs `limit` of 20 or less) each returned campaign's own switch
|
|
9804
|
-
* (`platformCampaignStatus`) is read live. Live reads cover TikTok, Meta, Google and
|
|
9827
|
+
* (`platformCampaignStatus`) is read live. Live reads cover TikTok, Meta, Google, OpenAI and Reddit.
|
|
9805
9828
|
* The rolled-up `status` is not re-derived by a live read.
|
|
9806
9829
|
*
|
|
9807
9830
|
* **Budgets here are SYNCED**, never read live, including with `live=true`. To read the
|
|
@@ -9828,7 +9851,14 @@ export const listAdCampaigns = <ThrowOnError extends boolean = false>(options?:
|
|
|
9828
9851
|
* accepts `portfolioBidStrategyId` instead. Google, X and OpenAI require a budget
|
|
9829
9852
|
* (422 without one; OpenAI accepts daily or lifetime, Google only
|
|
9830
9853
|
* `budgetType: daily`). On OpenAI `goal` sets the campaign objective, and
|
|
9831
|
-
* `conversions` needs an active standard conversion event on the account.
|
|
9854
|
+
* `conversions` needs an active standard conversion event on the account. On Reddit
|
|
9855
|
+
* `goal` is one of traffic, awareness, conversions, video_views or lead_generation
|
|
9856
|
+
* (422 otherwise) and the budget is optional: with one, the campaign uses Reddit's
|
|
9857
|
+
* campaign budget optimization and carries the pixel (see `promotedObject`, which then
|
|
9858
|
+
* needs `customEventType` for `conversions`), daily or lifetime (a lifetime budget
|
|
9859
|
+
* needs `endDate`, 400 otherwise). `startDate` / `endDate` set the campaign's schedule
|
|
9860
|
+
* and need that campaign budget (400 without one). Without a budget, each ad set
|
|
9861
|
+
* carries its own budget and dates. LinkedIn creates the
|
|
9832
9862
|
* campaign GROUP (our campaign level) and rejects a budget, which lives on the
|
|
9833
9863
|
* campaign (ad set) level there; it comes back `status: DRAFT`. Created `PAUSED`
|
|
9834
9864
|
* (TikTok `DISABLE`) unless `status: ACTIVE` where the platform supports it.
|
|
@@ -9990,8 +10020,8 @@ export const getAdCampaignDetails = <ThrowOnError extends boolean = false>(optio
|
|
|
9990
10020
|
* | `networkSettings` | 400 | Search only | 400 |
|
|
9991
10021
|
* | `trackingUrlTemplate`, `finalUrlSuffix` | 400 | Yes | 400 |
|
|
9992
10022
|
* | `sharedBudgetId` | 400 | Yes | 400 |
|
|
9993
|
-
* | `budget` (CBO; ABO returns 409) | Yes | Daily only | OpenAI: daily or lifetime; others 501 |
|
|
9994
|
-
* | `name` | Yes | 501 | 501 |
|
|
10023
|
+
* | `budget` (CBO; ABO returns 409) | Yes | Daily only | OpenAI and Reddit: daily or lifetime; others 501 |
|
|
10024
|
+
* | `name` | Yes | 501 | Reddit: Yes; others 501 |
|
|
9995
10025
|
* | `platformSpecificData.spendCap` | Yes | 400 | 400 |
|
|
9996
10026
|
* | `accountId` (empty campaigns) | Yes | - | - |
|
|
9997
10027
|
*
|
|
@@ -10032,6 +10062,12 @@ export const getAdCampaignDetails = <ThrowOnError extends boolean = false>(optio
|
|
|
10032
10062
|
* currency (422 below it). Lifetime can switch to daily, but OpenAI never switches a
|
|
10033
10063
|
* daily cap back to lifetime (422).
|
|
10034
10064
|
*
|
|
10065
|
+
* Reddit Ads: `budget` changes the amount of a campaign budget (Reddit campaign budget
|
|
10066
|
+
* optimization); a campaign whose ad groups carry the budget returns 409 or 422, use
|
|
10067
|
+
* PUT /v1/ads/ad-sets/{adSetId} there. Reddit cannot switch a published budget between
|
|
10068
|
+
* daily and lifetime, so `budget.type` must match the current one (422 otherwise).
|
|
10069
|
+
* `bidStrategy` is set per ad group on Reddit (PUT /v1/ads/ad-sets/{adSetId}).
|
|
10070
|
+
*
|
|
10035
10071
|
* `accountId` forwards the update straight to Meta for a campaign with zero ads,
|
|
10036
10072
|
* which would otherwise 404; the response then carries `updated: 0`.
|
|
10037
10073
|
*
|
|
@@ -10064,6 +10100,10 @@ export const updateAdCampaign = <ThrowOnError extends boolean = false>(options:
|
|
|
10064
10100
|
* account and retry. Other platforms answer 501 for an empty campaign.
|
|
10065
10101
|
* `accountId` is ignored when the campaign does have ads.
|
|
10066
10102
|
*
|
|
10103
|
+
* Reddit Ads has no delete: the campaign is archived instead (`configured_status`
|
|
10104
|
+
* ARCHIVED), which stops delivery for good. Its ad groups and ads keep their own
|
|
10105
|
+
* switches but cannot deliver under an archived campaign.
|
|
10106
|
+
*
|
|
10067
10107
|
*/
|
|
10068
10108
|
export const deleteAdCampaign = <ThrowOnError extends boolean = false>(options: OptionsLegacyParser<DeleteAdCampaignData, ThrowOnError>) => {
|
|
10069
10109
|
return (options?.client ?? client).delete<DeleteAdCampaignResponse, DeleteAdCampaignError, ThrowOnError>({
|
|
@@ -10297,7 +10337,7 @@ export const updateCampaignTargeting = <ThrowOnError extends boolean = false>(op
|
|
|
10297
10337
|
* (null when the read failed and the stored values were returned).
|
|
10298
10338
|
* With `live=true` (which needs a `campaignId` or `adSetId` filter) each listed ad set's own
|
|
10299
10339
|
* switch (`platformAdSetStatus`) is read live, for the first 20 rows; later rows keep their
|
|
10300
|
-
* synced value with `statusReadAt: null`. Live reads cover TikTok, Meta, Google and
|
|
10340
|
+
* synced value with `statusReadAt: null`. Live reads cover TikTok, Meta, Google, OpenAI and Reddit.
|
|
10301
10341
|
* The rolled-up `status` is not re-derived by a live read. On TikTok the same live read also
|
|
10302
10342
|
* returns the ad group's applied `optimizationGoal` and `billingEvent`, as TikTok's adgroup/get
|
|
10303
10343
|
* reports them, so you can verify the goal TikTok applied rather than the one you requested.
|
|
@@ -10443,6 +10483,14 @@ export const getAdSetDetails = <ThrowOnError extends boolean = false>(options: O
|
|
|
10443
10483
|
* CBO, the response is 409 with code BUDGET_LEVEL_MISMATCH. Route to
|
|
10444
10484
|
* PUT /v1/ads/campaigns/{campaignId} instead.
|
|
10445
10485
|
*
|
|
10486
|
+
* Reddit Ads: `budget` changes the ad group's amount; an ad group that spends its
|
|
10487
|
+
* campaign budget returns 422 (update the campaign instead), and Reddit cannot switch
|
|
10488
|
+
* a published budget between daily and lifetime, so `budget.type` must match the
|
|
10489
|
+
* current one (422 otherwise). `name` renames the ad group. `bidStrategy` maps to the
|
|
10490
|
+
* ad group's `bid_strategy`: LOWEST_COST_WITHOUT_CAP = automatic bidding (BIDLESS),
|
|
10491
|
+
* LOWEST_COST_WITH_BID_CAP = MANUAL_BIDDING with `bidAmount` as the bid, COST_CAP =
|
|
10492
|
+
* MAXIMIZE_VOLUME with `bidAmount` as the cap; LOWEST_COST_WITH_MIN_ROAS returns 422.
|
|
10493
|
+
*
|
|
10446
10494
|
* `status` behaves exactly as PUT /v1/ads/ad-sets/{adSetId}/status
|
|
10447
10495
|
* describes: only the ad set's own switch is written, its ads keep
|
|
10448
10496
|
* theirs, and `statusUpdated` / `statusSkipped` report whether that switch
|
|
@@ -10464,7 +10512,7 @@ export const updateAdSet = <ThrowOnError extends boolean = false>(options: Optio
|
|
|
10464
10512
|
* `status: cancelled`.
|
|
10465
10513
|
*
|
|
10466
10514
|
* Delete is soft on platforms that have no hard delete: LinkedIn moves the
|
|
10467
|
-
* campaign to `PENDING_DELETION`, Pinterest
|
|
10515
|
+
* campaign to `PENDING_DELETION`, Pinterest and Reddit archive the ad group, and X
|
|
10468
10516
|
* soft-flags the line item. Google removes the ad group. All remain readable
|
|
10469
10517
|
* for reporting.
|
|
10470
10518
|
*
|
|
@@ -10488,7 +10536,7 @@ export const deleteAdSet = <ThrowOnError extends boolean = false>(options: Optio
|
|
|
10488
10536
|
* Writes the ad set's own on/off switch and nothing else, on every platform
|
|
10489
10537
|
* (Meta `configured_status`, TikTok ad group `operation_status`, Google ad
|
|
10490
10538
|
* group status, LinkedIn campaign, Pinterest ad group, X line item, ChatGPT
|
|
10491
|
-
* (OpenAI) ad group). Its ads keep their own switches: an ad you paused
|
|
10539
|
+
* (OpenAI) ad group, Reddit ad group `configured_status`). Its ads keep their own switches: an ad you paused
|
|
10492
10540
|
* individually stays paused when the ad set resumes. The campaign above is
|
|
10493
10541
|
* not touched either, so an ad set resumed under a paused campaign reads
|
|
10494
10542
|
* `status: paused` until the campaign is resumed too. See the Status model
|
|
@@ -10660,6 +10708,12 @@ export const getAd = <ThrowOnError extends boolean = false>(options: OptionsLega
|
|
|
10660
10708
|
* - **Pinterest / X / OpenAI Ads**: status + budget only. Sending
|
|
10661
10709
|
* `targeting` or `creative` returns 501 with code `unsupported_platform_operation`.
|
|
10662
10710
|
* OpenAI Ads budget is the campaign's spend cap, daily or lifetime (see `budget.type` below).
|
|
10711
|
+
* - **Reddit Ads**: status, budget, `name` (renames the ad) and targeting. `budget` goes to
|
|
10712
|
+
* the ad's ad group, or to its campaign when the ad group spends a campaign budget, and
|
|
10713
|
+
* keeps its daily or lifetime type (422 to switch). `targeting` REPLACES the ad group's
|
|
10714
|
+
* whole targeting (geo, communities, conversation keywords, interests, audiences,
|
|
10715
|
+
* languages, gender), so it applies to every ad in the ad group. `creative` returns 501:
|
|
10716
|
+
* a Reddit ad runs a post, so create a new ad with the new creative instead.
|
|
10663
10717
|
*
|
|
10664
10718
|
* **Google location and language replacement:** locations, languages and devices are
|
|
10665
10719
|
* campaign-level criteria on Google, so these edits apply to every ad group and ad in
|
|
@@ -10718,7 +10772,7 @@ export const updateAd = <ThrowOnError extends boolean = false>(options: OptionsL
|
|
|
10718
10772
|
* Cancel an ad
|
|
10719
10773
|
* Deletes an ad on the platform while keeping its history, and removes empty parents only when they were created through this API.
|
|
10720
10774
|
*
|
|
10721
|
-
* Deletes the ad on the platform and marks it as cancelled in the database. The ad is preserved for history. OpenAI Ads has no delete API; the ad is archived instead (a terminal state, the closest equivalent).
|
|
10775
|
+
* Deletes the ad on the platform and marks it as cancelled in the database. The ad is preserved for history. OpenAI Ads has no delete API; the ad is archived instead (a terminal state, the closest equivalent). Reddit Ads has no delete either: the ad is archived (`configured_status` ARCHIVED).
|
|
10722
10776
|
*
|
|
10723
10777
|
* Only the ad is deleted; a campaign or ad set is never deleted while it still holds another ad. On Meta, when the ad set and campaign were created by Zernio (by `POST /v1/ads/create` or `POST /v1/ads/boost`) and Meta lists no other ad in the ad set (archived ads count), the emptied ad set is deleted too, then the campaign once it holds no other ad set. Parents created outside Zernio, and the parents of an ad imported from the platform, are always kept. On LinkedIn the ad is a creative inside a campaign inside a campaign group: the creative is always removed, the campaign only when Zernio created it and LinkedIn lists no other creative in it that is not archived, canceled or deleted, and the campaign group only when Zernio created it and LinkedIn lists no other campaign in it that is not canceled or deleted (archived campaigns count). If the creative itself cannot be removed the request fails and no parent is touched. On X the ad is a promoted post inside a line item inside a campaign: the promoted post is always removed, the line item only when Zernio created it (by `POST /v1/ads/create` or `POST /v1/ads/boost`) and X lists no other undeleted promoted post in it, and the campaign only when Zernio created it and X lists no other undeleted line item in it. If X refuses the promoted post delete the request fails and no parent is touched. To delete a whole campaign on purpose use `DELETE /v1/ads/campaigns/{campaignId}`.
|
|
10724
10778
|
*
|
|
@@ -10736,7 +10790,7 @@ export const deleteAd = <ThrowOnError extends boolean = false>(options: OptionsL
|
|
|
10736
10790
|
*
|
|
10737
10791
|
* Ad-scoped pause/resume: flips ONLY this ad's own switch (Meta
|
|
10738
10792
|
* `configured_status`, TikTok `operation_status`, Google ad group ad
|
|
10739
|
-
* status, LinkedIn creative, Pinterest ad), never its parent ad set or
|
|
10793
|
+
* status, LinkedIn creative, Pinterest ad, Reddit ad `configured_status`), never its parent ad set or
|
|
10740
10794
|
* campaign, so sibling ads keep running. X is the exception: its smallest
|
|
10741
10795
|
* switch is the line item. Thin wrapper over the `status` field of
|
|
10742
10796
|
* PUT /v1/ads/{adId}, for callers that want a URL symmetric to
|
|
@@ -12434,6 +12488,9 @@ export const createAdAccount = <ThrowOnError extends boolean = false>(options: O
|
|
|
12434
12488
|
* For Google Ads: responds `429` when Google's API quota is temporarily exhausted
|
|
12435
12489
|
* (instead of an empty list). Retry after a delay.
|
|
12436
12490
|
*
|
|
12491
|
+
* For Reddit Ads (`redditads`): every Reddit ad account the connected Reddit user can reach,
|
|
12492
|
+
* with `businessId`, `approvalStatus` (Reddit's `admin_approval`), `timezone` and `type`.
|
|
12493
|
+
*
|
|
12437
12494
|
*/
|
|
12438
12495
|
export const listAdAccounts = <ThrowOnError extends boolean = false>(options: OptionsLegacyParser<ListAdAccountsData, ThrowOnError>) => {
|
|
12439
12496
|
return (options?.client ?? client).get<ListAdAccountsResponse, ListAdAccountsError, ThrowOnError>({
|
|
@@ -12550,6 +12607,22 @@ export const getDsaRecommendations = <ThrowOnError extends boolean = false>(opti
|
|
|
12550
12607
|
* `postId` on an X Ads connection resolves through its X account, and is
|
|
12551
12608
|
* a 400 when the profile has none (pass `platformPostId` instead).
|
|
12552
12609
|
*
|
|
12610
|
+
* **Reddit.** `accountId` is the Reddit Ads connection (platform `redditads`).
|
|
12611
|
+
* Pass the Reddit post as `platformPostId` (`t3_abc123` or the bare id), or a
|
|
12612
|
+
* Zernio `postId`, which resolves through the Reddit account connected on the
|
|
12613
|
+
* same profile (400 when there is none). Reddit promotes only posts made by a
|
|
12614
|
+
* profile of the ad account: a post by any other author returns 422. Goals are
|
|
12615
|
+
* traffic, awareness, conversions, video_views (the post must be a video, 422
|
|
12616
|
+
* otherwise) and lead_generation; conversions and lead_generation need a pixel
|
|
12617
|
+
* that already received the event (see `promotedObject`). `leadGenFormId` returns
|
|
12618
|
+
* 400: Reddit retired its native lead forms, so `lead_generation` sends people to
|
|
12619
|
+
* `linkUrl` and optimizes toward the pixel's Lead event. Each boost creates a
|
|
12620
|
+
* campaign, an ad group carrying the budget, the targeting and the bid, and the ad.
|
|
12621
|
+
* `bidStrategy` sets the ad group's bid: LOWEST_COST_WITHOUT_CAP (or omitted) is
|
|
12622
|
+
* automatic bidding (BIDLESS), LOWEST_COST_WITH_BID_CAP is MANUAL_BIDDING with
|
|
12623
|
+
* `bidAmount` as the bid, COST_CAP is MAXIMIZE_VOLUME with `bidAmount` as the cap; any
|
|
12624
|
+
* other strategy returns 422 before anything is created.
|
|
12625
|
+
*
|
|
12553
12626
|
* **Messaging boosts (Meta).** Use `goal: engagement` with
|
|
12554
12627
|
* `callToAction: WHATSAPP_MESSAGE`, `MESSAGE_PAGE`, or `INSTAGRAM_MESSAGE`.
|
|
12555
12628
|
* The CTA implies WHATSAPP, MESSENGER, or INSTAGRAM_DIRECT respectively;
|
|
@@ -12684,7 +12757,7 @@ export const replaceGoogleListingGroupFilters = <ThrowOnError extends boolean =
|
|
|
12684
12757
|
* Create standalone ad
|
|
12685
12758
|
* Creates a paid ad with your own creative, building the campaign and ad set it needs or adding it to existing ones.
|
|
12686
12759
|
*
|
|
12687
|
-
* Create a paid ad with custom creative across Meta, Google Ads, Pinterest, TikTok, X, LinkedIn,
|
|
12760
|
+
* Create a paid ad with custom creative across Meta, Google Ads, Pinterest, TikTok, X, LinkedIn, OpenAI Ads (ChatGPT Ads) and Reddit Ads.
|
|
12688
12761
|
*
|
|
12689
12762
|
* Google Performance Max: set `campaignType: "pmax"` and supply `assetGroup` with
|
|
12690
12763
|
* text, images by role, business name and finalUrl. Creates a daily budget, PAUSED
|
|
@@ -12737,6 +12810,8 @@ export const replaceGoogleListingGroupFilters = <ThrowOnError extends boolean =
|
|
|
12737
12810
|
*
|
|
12738
12811
|
* 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`.
|
|
12739
12812
|
*
|
|
12813
|
+
* Reddit Ads (`accountId` of a `redditads` connection, `adAccountId` like `a2_abc123`) creates a campaign, an ad group carrying the budget, schedule, targeting and pixel, and an ad running a new promoted post authored by the ad account's first profile (422 when it has none). The creative format follows the body: `carouselCards` builds a carousel, `video` a video ad, `imageUrl` an image ad, and none of them a text ad, which cannot link out (`linkUrl` is a 400 there; `body` is required). Only the legacy single-creative shape is available: `creatives[]`, `adSetId`, `existingCampaignId` and `validateOnly` are refused. Reddit throttling surfaces as 429 `rate_limited` with `platform: reddit`; retry after a delay. To promote an existing Reddit post use POST /v1/ads/boost.
|
|
12814
|
+
*
|
|
12740
12815
|
* **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.
|
|
12741
12816
|
*
|
|
12742
12817
|
*/
|
|
@@ -13043,6 +13118,11 @@ export const searchAdInterests = <ThrowOnError extends boolean = false>(options:
|
|
|
13043
13118
|
* ids feed `TargetingSpec.workPositions`/`workEmployers`/`workIndustries`
|
|
13044
13119
|
* - `industry`, `jobFunction`, `seniority`, `companySize`: the LinkedIn-only B2B facets, whose
|
|
13045
13120
|
* URNs feed `TargetingSpec.industries`/`jobFunctions`/`seniorities`/`companySizes`
|
|
13121
|
+
* - `community`: Reddit only. Subreddits matching `q`; the id is the subreddit name for
|
|
13122
|
+
* `TargetingSpec.communities` / `excludedCommunities`, `platformId` Reddit's own id and
|
|
13123
|
+
* `audienceSize` its subscriber count when Reddit reports it
|
|
13124
|
+
* - `conversationKeyword`: Reddit only. Reddit's keyword suggestions for the seed `q`; the id is
|
|
13125
|
+
* the keyword for `TargetingSpec.conversationKeywords` / `excludedConversationKeywords`
|
|
13046
13126
|
*
|
|
13047
13127
|
* Availability of each dimension varies by platform. A dimension a platform cannot search
|
|
13048
13128
|
* returns a 400 naming `dimension`; it never falls back to another dimension, and every
|
|
@@ -13062,7 +13142,7 @@ export const searchAdInterests = <ThrowOnError extends boolean = false>(options:
|
|
|
13062
13142
|
* at 20, with no network call; its ids feed `TargetingSpec.languages`.
|
|
13063
13143
|
*
|
|
13064
13144
|
* Results are normalized across platforms into a single shape, so the same client code
|
|
13065
|
-
* consumes Meta, TikTok, LinkedIn, X, Pinterest, and
|
|
13145
|
+
* consumes Meta, TikTok, LinkedIn, X, Pinterest, Google and Reddit results.
|
|
13066
13146
|
*
|
|
13067
13147
|
* TikTok geo searches return every matching level in one list (`type` is
|
|
13068
13148
|
* `country`, `region`, `city`, `district`, or `metro` for DMA areas), and
|
|
@@ -13124,6 +13204,15 @@ export const searchAdInterests = <ThrowOnError extends boolean = false>(options:
|
|
|
13124
13204
|
* exposes no postal-code catalog, pass postal codes directly as
|
|
13125
13205
|
* `targeting.zips: [{ key }]` on `POST /v1/ads/create`
|
|
13126
13206
|
*
|
|
13207
|
+
* Reddit (`redditads` connection) searches `geo`, `interest`, `community` and
|
|
13208
|
+
* `conversationKeyword`; any other dimension returns 400. Its geo search honours `geoType`
|
|
13209
|
+
* `city` (the default, a server-side city search), `zip` (`q` is the postal code), `country`,
|
|
13210
|
+
* `region` and `metro_area` (matched in Zernio against Reddit's geolocation catalog) and
|
|
13211
|
+
* `all`; other values return 400. `countryCode` scopes every geo search. Each result's id is
|
|
13212
|
+
* Reddit's geolocation id, usable as a `regions`/`metros`/`cities`/`zips` `key` (country
|
|
13213
|
+
* ids go in `countries`). `interest` matches Reddit's interest catalog in Zernio, with the
|
|
13214
|
+
* category as `path`.
|
|
13215
|
+
*
|
|
13127
13216
|
* For geo queries, `q` should contain only the locality name (e.g. `"Amsterdam"`,
|
|
13128
13217
|
* not `"Amsterdam, NL"`). Use `countryCode` to disambiguate.
|
|
13129
13218
|
*
|
|
@@ -13736,6 +13825,7 @@ export const getConversionsQuality = <ThrowOnError extends boolean = false>(opti
|
|
|
13736
13825
|
* - TikTok (`tiktokads`) via the Offline Events API `/offline/batch/` (OFFLINE conversions only)
|
|
13737
13826
|
* - OpenAI Ads (`openaiads`) via its Conversions API (a separate host, `bzr.openai.com`)
|
|
13738
13827
|
* - Pinterest (`pinterestads`) via `POST /v5/ad_accounts/{id}/events`
|
|
13828
|
+
* - Reddit (`redditads`) via the Reddit Conversions API (`POST /api/v3/pixels/{pixelId}/conversion_events`)
|
|
13739
13829
|
*
|
|
13740
13830
|
* `destinationId` semantics differ per platform:
|
|
13741
13831
|
*
|
|
@@ -13745,6 +13835,7 @@ export const getConversionsQuality = <ThrowOnError extends boolean = false>(opti
|
|
|
13745
13835
|
* - TikTok: Offline Event Set ID, e.g. `7057103914977558530`
|
|
13746
13836
|
* - OpenAI Ads: pixel wire id (numeric `pixel_id`, distinct from the internal pixel id), as returned by `GET /v1/accounts/{accountId}/conversion-destinations`
|
|
13747
13837
|
* - Pinterest: numeric ad account id, e.g. `549755885175` (Pinterest attributes to the ad account, not to a tag)
|
|
13838
|
+
* - Reddit: pixel id, e.g. `a2_abc123`, as returned by `GET /v1/accounts/{accountId}/conversion-destinations` (any other shape returns 400)
|
|
13748
13839
|
*
|
|
13749
13840
|
* Pinterest notes: each event needs an `email`, or `ipAddress` plus `userAgent`; others are
|
|
13750
13841
|
* listed in `failures` with code `INVALID_EVENT` and the rest are still sent. `clickIds.epik`
|
|
@@ -13754,6 +13845,21 @@ export const getConversionsQuality = <ThrowOnError extends boolean = false>(opti
|
|
|
13754
13845
|
* (failures carry code `PINTEREST_EVENT_FAILED`). `consent.adUserData: DENIED` sets `opt_out`.
|
|
13755
13846
|
* The connected user needs a Business Access role on the ad account (403 otherwise).
|
|
13756
13847
|
*
|
|
13848
|
+
* Reddit notes: each event needs a match key: `clickIds.rdt_cid`, `clickIds.rdt_uuid`,
|
|
13849
|
+
* `email`, `phone`, `externalId`, or `ipAddress` plus `userAgent`. Reddit accepts events up to
|
|
13850
|
+
* 7 days old, and `eventTime` is unix SECONDS (a value more than an hour in the future is
|
|
13851
|
+
* refused as milliseconds). Events failing these checks are listed in `failures` with code
|
|
13852
|
+
* `INVALID_EVENT` and the rest are still sent. Email (lowercased, dots and `+tags` stripped
|
|
13853
|
+
* from the local part), phone (E.164 with the leading `+`) and `externalId` are SHA-256
|
|
13854
|
+
* hashed; IP and user agent go plaintext. `consent.adUserData: DENIED` sends no user fields.
|
|
13855
|
+
* `actionSource` maps to WEBSITE (`web`), APP (`app`) or OTHER, overridable with
|
|
13856
|
+
* `platformData.action_source`; `platformData.order_id` is forwarded. `testCode` is sent as
|
|
13857
|
+
* Reddit's `test_id`. The connection must hold the `adsconversions` permission: one
|
|
13858
|
+
* authorized without it returns 403 `reconnect_required` (reconnect via
|
|
13859
|
+
* GET /v1/connect/redditads/ads), and a Reddit user with no role on the ad account that owns
|
|
13860
|
+
* the pixel returns 403 `insufficient_permissions`. Reddit throttling and other rejections are
|
|
13861
|
+
* reported per chunk in `failures` with code `REDDIT_REJECTED`.
|
|
13862
|
+
*
|
|
13757
13863
|
* TikTok notes: this path sends OFFLINE conversions (in-store / CRM / call-center), not web-pixel
|
|
13758
13864
|
* events. Each event must carry an email or phone (TikTok requires at least one). The connected
|
|
13759
13865
|
* TikTok ads account must have granted the Offline Events permission; older grants must reconnect.
|
|
@@ -13776,10 +13882,11 @@ export const getConversionsQuality = <ThrowOnError extends boolean = false>(opti
|
|
|
13776
13882
|
* entire batch if any event is malformed. Google caps at 2000. LinkedIn caps at 5000 and is
|
|
13777
13883
|
* also all-or-nothing per chunk. OpenAI Ads caps at 1000 per request; larger submissions are
|
|
13778
13884
|
* split into 1000-event chunks, each all-or-nothing (a malformed event fails every event in
|
|
13779
|
-
* that chunk, not the whole request).
|
|
13885
|
+
* that chunk, not the whole request). Reddit works the same way, in chunks of 1000.
|
|
13780
13886
|
*
|
|
13781
13887
|
* Dedup: pass a stable `eventId` on every event. Meta and LinkedIn use it to dedupe against
|
|
13782
|
-
* browser-side pixel/Insight Tag events; Google maps it to `transactionId
|
|
13888
|
+
* browser-side pixel/Insight Tag events; Google maps it to `transactionId`; Reddit receives it as
|
|
13889
|
+
* `conversion_id`, its dedup key against Reddit Pixel events.
|
|
13783
13890
|
*
|
|
13784
13891
|
* Per-platform `eventName` semantics:
|
|
13785
13892
|
*
|
|
@@ -14033,15 +14140,19 @@ export const updateCampaignConversionGoals = <ThrowOnError extends boolean = fal
|
|
|
14033
14140
|
* Lists where an ad account can receive conversion events (pixels, conversion actions or rules), so you know where to send them.
|
|
14034
14141
|
*
|
|
14035
14142
|
* Returns the list of pixels (Meta), conversion actions (Google),
|
|
14036
|
-
* conversion rules (LinkedIn), pixels (OpenAI Ads) or ad accounts
|
|
14143
|
+
* conversion rules (LinkedIn), pixels (OpenAI Ads, Reddit) or ad accounts
|
|
14037
14144
|
* (Pinterest) accessible to the connected ads account. Use the returned `id` as `destinationId` when
|
|
14038
14145
|
* posting to `POST /v1/ads/conversions`.
|
|
14039
14146
|
*
|
|
14040
14147
|
* For Google and LinkedIn, each destination's `type` reflects the
|
|
14041
14148
|
* conversion type (PURCHASE, LEAD, SIGN_UP, etc.), and the event type is
|
|
14042
|
-
* locked to the destination. For Meta
|
|
14149
|
+
* locked to the destination. For Meta, OpenAI Ads and Reddit, `type` is absent:
|
|
14043
14150
|
* pixels accept any event name per request.
|
|
14044
14151
|
*
|
|
14152
|
+
* For Reddit, the pixels of every ad account the connection reaches (only the scoped
|
|
14153
|
+
* ones when the connection has an ad-account scope), each with the `adAccountId` that owns
|
|
14154
|
+
* it. Reddit pixels are created in Reddit Ads Manager, not through Zernio.
|
|
14155
|
+
*
|
|
14045
14156
|
* For LinkedIn, destinations are returned across every sponsored ad
|
|
14046
14157
|
* account the connected token can access; the `adAccountId` field on
|
|
14047
14158
|
* each destination identifies the parent ad account and is required for
|
|
@@ -14063,7 +14174,7 @@ export const listConversionDestinations = <ThrowOnError extends boolean = false>
|
|
|
14063
14174
|
* LinkedIn (conversion rule) and Google Ads (conversion action). Meta
|
|
14064
14175
|
* and OpenAI Ads pixels are created via their own tracking-tags flow
|
|
14065
14176
|
* instead (`POST /v1/accounts/{accountId}/tracking-tags`); this endpoint
|
|
14066
|
-
* returns 405 for both.
|
|
14177
|
+
* returns 405 for both, and for Reddit (create Reddit pixels in Reddit Ads Manager).
|
|
14067
14178
|
*
|
|
14068
14179
|
* **LinkedIn:** creation is NOT idempotent. A retry creates a second
|
|
14069
14180
|
* destination. Deduplicate before retrying.
|