zernio-sdk 0.0.552 → 0.0.553

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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -0
  3. data/docs/AdCampaignsApi.md +3 -3
  4. data/docs/ConnectApi.md +70 -0
  5. data/docs/ConnectOpenAIAdsCredentials200Response.md +22 -0
  6. data/docs/ConnectOpenAIAdsCredentialsRequest.md +24 -0
  7. data/docs/ConversionEvent.md +1 -1
  8. data/docs/ConversionsApi.md +5 -5
  9. data/docs/CreateStandaloneAdRequest.md +8 -8
  10. data/docs/CreateTrackingTagRequest.md +1 -1
  11. data/docs/GetTrackingTag200Response.md +20 -0
  12. data/docs/ListConversionDestinations200ResponseDestinationsInner.md +1 -1
  13. data/docs/SendConversions200Response.md +1 -1
  14. data/docs/SendConversionsRequest.md +3 -3
  15. data/docs/TrackingTagsApi.md +17 -17
  16. data/docs/UpdateAdRequestBudget.md +1 -1
  17. data/lib/zernio-sdk/api/ad_campaigns_api.rb +10 -10
  18. data/lib/zernio-sdk/api/connect_api.rb +68 -0
  19. data/lib/zernio-sdk/api/conversions_api.rb +8 -8
  20. data/lib/zernio-sdk/api/tracking_tags_api.rb +18 -18
  21. data/lib/zernio-sdk/models/account_with_follower_stats.rb +2 -2
  22. data/lib/zernio-sdk/models/ad.rb +2 -2
  23. data/lib/zernio-sdk/models/ad_campaign.rb +2 -2
  24. data/lib/zernio-sdk/models/ad_tree_campaign.rb +2 -2
  25. data/lib/zernio-sdk/models/bulk_update_ad_campaign_status_request_campaigns_inner.rb +2 -2
  26. data/lib/zernio-sdk/models/connect_open_ai_ads_credentials200_response.rb +165 -0
  27. data/lib/zernio-sdk/models/connect_open_ai_ads_credentials_request.rb +212 -0
  28. data/lib/zernio-sdk/models/conversion_event.rb +1 -1
  29. data/lib/zernio-sdk/models/create_standalone_ad_request.rb +8 -8
  30. data/lib/zernio-sdk/models/create_tracking_tag201_response.rb +2 -2
  31. data/lib/zernio-sdk/models/create_tracking_tag_request.rb +1 -1
  32. data/lib/zernio-sdk/models/get_tracking_tag200_response.rb +190 -0
  33. data/lib/zernio-sdk/models/list_conversion_destinations200_response.rb +2 -2
  34. data/lib/zernio-sdk/models/list_conversion_destinations200_response_destinations_inner.rb +1 -1
  35. data/lib/zernio-sdk/models/list_tracking_tags200_response.rb +2 -2
  36. data/lib/zernio-sdk/models/send_conversions200_response.rb +3 -3
  37. data/lib/zernio-sdk/models/send_conversions_request.rb +3 -3
  38. data/lib/zernio-sdk/models/social_account.rb +2 -2
  39. data/lib/zernio-sdk/models/update_ad_campaign_status_request.rb +2 -2
  40. data/lib/zernio-sdk/models/update_ad_request_budget.rb +1 -0
  41. data/lib/zernio-sdk/models/update_ad_set_request.rb +2 -2
  42. data/lib/zernio-sdk/version.rb +1 -1
  43. data/lib/zernio-sdk.rb +3 -0
  44. data/openapi.yaml +165 -65
  45. data/spec/api/ad_campaigns_api_spec.rb +3 -3
  46. data/spec/api/connect_api_spec.rb +12 -0
  47. data/spec/api/conversions_api_spec.rb +4 -4
  48. data/spec/api/tracking_tags_api_spec.rb +8 -8
  49. data/spec/models/account_with_follower_stats_spec.rb +1 -1
  50. data/spec/models/ad_campaign_spec.rb +1 -1
  51. data/spec/models/ad_spec.rb +1 -1
  52. data/spec/models/ad_tree_campaign_spec.rb +1 -1
  53. data/spec/models/bulk_update_ad_campaign_status_request_campaigns_inner_spec.rb +1 -1
  54. data/spec/models/connect_open_ai_ads_credentials200_response_spec.rb +48 -0
  55. data/spec/models/connect_open_ai_ads_credentials_request_spec.rb +54 -0
  56. data/spec/models/create_tracking_tag201_response_spec.rb +1 -1
  57. data/spec/models/get_tracking_tag200_response_spec.rb +46 -0
  58. data/spec/models/list_conversion_destinations200_response_spec.rb +1 -1
  59. data/spec/models/list_tracking_tags200_response_spec.rb +1 -1
  60. data/spec/models/send_conversions200_response_spec.rb +1 -1
  61. data/spec/models/social_account_spec.rb +1 -1
  62. data/spec/models/update_ad_campaign_status_request_spec.rb +1 -1
  63. data/spec/models/update_ad_set_request_spec.rb +1 -1
  64. metadata +13 -1
data/openapi.yaml CHANGED
@@ -5393,7 +5393,7 @@ components:
5393
5393
  _id: { type: string }
5394
5394
  platform:
5395
5395
  type: string
5396
- enum: [tiktok, instagram, facebook, youtube, linkedin, twitter, threads, pinterest, reddit, bluesky, googlebusiness, telegram, snapchat, discord, whatsapp, linkedinads, metaads, pinterestads, tiktokads, xads, googleads]
5396
+ enum: [tiktok, instagram, facebook, youtube, linkedin, twitter, threads, pinterest, reddit, bluesky, googlebusiness, telegram, snapchat, discord, whatsapp, linkedinads, metaads, pinterestads, tiktokads, xads, googleads, openaiads]
5397
5397
  profileId:
5398
5398
  oneOf:
5399
5399
  - type: string
@@ -6567,7 +6567,7 @@ components:
6567
6567
  properties:
6568
6568
  _id: { type: string }
6569
6569
  name: { type: string }
6570
- platform: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter] }
6570
+ platform: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter, openai] }
6571
6571
  status: { $ref: '#/components/schemas/AdStatus' }
6572
6572
  adType: { type: string, enum: [boost, standalone] }
6573
6573
  goal: { type: string, enum: [engagement, traffic, awareness, video_views, lead_generation, lead_conversion, conversions, app_promotion, catalog_sales, job_applicants], description: "Available goals vary by platform. Meta (Facebook/Instagram) supports all 9 (incl. `lead_conversion` = website pixel lead optimization and `catalog_sales` = Advantage+ catalog ads). TikTok supports the 7 non-`lead_conversion` goals. LinkedIn supports all except app_promotion / lead_conversion. Twitter/X supports engagement, traffic, awareness, video_views, app_promotion. Pinterest and Google Ads support only engagement, traffic, awareness, video_views." }
@@ -6748,7 +6748,7 @@ components:
6748
6748
  description: Campaign with nested ad sets and rolled-up metrics
6749
6749
  properties:
6750
6750
  platformCampaignId: { type: string }
6751
- platform: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter] }
6751
+ platform: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter, openai] }
6752
6752
  campaignName: { type: string }
6753
6753
  status: { allOf: [{ $ref: '#/components/schemas/AdStatus' }], description: "Delivery status derived from child ad statuses. Distinct from `reviewStatus`, which reflects the platform-side review state." }
6754
6754
  reviewStatus:
@@ -6831,7 +6831,7 @@ components:
6831
6831
  type: object
6832
6832
  properties:
6833
6833
  platformCampaignId: { type: string }
6834
- platform: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter] }
6834
+ platform: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter, openai] }
6835
6835
  campaignName: { type: string }
6836
6836
  status: { allOf: [{ $ref: '#/components/schemas/AdStatus' }], description: "Delivery status derived from child ad statuses. Distinct from `reviewStatus`." }
6837
6837
  reviewStatus:
@@ -6913,12 +6913,14 @@ components:
6913
6913
  Standard event name (Purchase, Lead, CompleteRegistration, AddToCart,
6914
6914
  InitiateCheckout, AddPaymentInfo, Subscribe, StartTrial, ViewContent,
6915
6915
  Search, Contact, SubmitApplication, Schedule) or a custom string
6916
- (only supported on platforms that accept custom events — Meta).
6916
+ (only supported on platforms that accept custom events — Meta and
6917
+ OpenAI Ads).
6917
6918
 
6918
6919
  Per-platform behavior:
6919
6920
  - Meta: free-form; standard names match Meta's built-ins.
6920
6921
  - Google: ignored — the conversion action's category determines the type.
6921
6922
  - LinkedIn: ignored — the conversion rule's `type` is locked to the destination.
6923
+ - OpenAI Ads: a fixed subset of standard names (Purchase, Lead, AddToCart, ViewContent, InitiateCheckout, CompleteRegistration, Subscribe, StartTrial, Schedule) maps 1:1 onto OpenAI's own event-type enum; anything else is sent as a custom event with the name preserved.
6922
6924
  example: Purchase
6923
6925
  eventTime:
6924
6926
  type: integer
@@ -17552,6 +17554,63 @@ paths:
17552
17554
  '401': { $ref: '#/components/responses/Unauthorized' }
17553
17555
  '500': { description: Internal error }
17554
17556
 
17557
+ /v1/connect/openai-ads/credentials:
17558
+ post:
17559
+ operationId: connectOpenAIAdsCredentials
17560
+ tags: [Connect]
17561
+ summary: Connect an OpenAI Ads account
17562
+ description: |
17563
+ Connect an OpenAI Ads account using an API key from ChatGPT Ads Manager.
17564
+
17565
+ The key grants full campaign write access on OpenAI's side (OpenAI does
17566
+ not offer a read-only key scope). Zernio uses it to read ads and
17567
+ performance, and to create and manage campaigns you set up through
17568
+ Zernio (create, status, budget, and cancel). Campaigns created
17569
+ directly in ChatGPT Ads Manager can still be managed there.
17570
+ requestBody:
17571
+ required: true
17572
+ content:
17573
+ application/json:
17574
+ schema:
17575
+ type: object
17576
+ required: [apiKey, profileId]
17577
+ properties:
17578
+ apiKey:
17579
+ type: string
17580
+ description: "API key from ChatGPT Ads Manager (Settings). Grants full read/write access on OpenAI's side; Zernio only ever reads with it."
17581
+ profileId:
17582
+ type: string
17583
+ description: Your Zernio profile ID
17584
+ state:
17585
+ type: string
17586
+ description: Optional state passthrough for the connect flow.
17587
+ redirectUri:
17588
+ type: string
17589
+ format: uri
17590
+ description: Optional URL to redirect to after successful connection
17591
+ example:
17592
+ apiKey: "sk-ads-xxxxxxxxxxxxxxxxxxxx"
17593
+ profileId: "6507a1b2c3d4e5f6a7b8c9d0"
17594
+ responses:
17595
+ '200':
17596
+ description: OpenAI Ads connected successfully
17597
+ content:
17598
+ application/json:
17599
+ schema:
17600
+ type: object
17601
+ properties:
17602
+ accountId: { type: string }
17603
+ adAccountName: { type: string }
17604
+ redirectUrl: { type: string }
17605
+ example:
17606
+ accountId: "6507a1b2c3d4e5f6a7b8c9d0"
17607
+ adAccountName: "Acme US"
17608
+ '400': { $ref: '#/components/responses/BadRequest' }
17609
+ '401':
17610
+ description: "Unauthorized, or the API key could not read an OpenAI ad account (code invalid_credentials)."
17611
+ '403':
17612
+ description: Ads add-on required.
17613
+
17555
17614
  /v1/connect/whatsapp/credentials:
17556
17615
  post:
17557
17616
  operationId: connectWhatsAppCredentials
@@ -33322,7 +33381,7 @@ paths:
33322
33381
  - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 500, default: 50 } }
33323
33382
  - { name: source, in: query, schema: { type: string, enum: [zernio, all], default: all }, description: "all (default) = Zernio-created + platform-discovered ads. zernio = restrict to Zernio-created only." }
33324
33383
  - { name: status, in: query, schema: { $ref: '#/components/schemas/AdStatus' } }
33325
- - { name: platform, in: query, schema: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter] } }
33384
+ - { name: platform, in: query, schema: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter, openai] } }
33326
33385
  - { name: accountId, in: query, schema: { type: string }, description: Social account ID }
33327
33386
  - { name: adAccountId, in: query, schema: { type: string }, description: "Platform ad account ID (e.g. act_123 for Meta). Mirrors the same filter on /v1/ads/campaigns and /v1/ads/tree." }
33328
33387
  - { name: profileId, in: query, schema: { type: string }, description: Profile ID }
@@ -33370,7 +33429,7 @@ paths:
33370
33429
  - $ref: '#/components/parameters/PageParam'
33371
33430
  - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 100, default: 20 } }
33372
33431
  - { name: source, in: query, schema: { type: string, enum: [zernio, all], default: all }, description: "`all` (default) returns both Zernio-created ads and those discovered from the platform's ad manager — matches the web UI's default view. Pass `zernio` to restrict to isExternal=false only. Status is NOT filtered by default — use the `status` param for that." }
33373
- - { name: platform, in: query, schema: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter] } }
33432
+ - { name: platform, in: query, schema: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter, openai] } }
33374
33433
  - { name: status, in: query, schema: { $ref: '#/components/schemas/AdStatus' }, description: Filter by derived campaign status (post-aggregation) }
33375
33434
  - { name: adAccountId, in: query, schema: { type: string }, description: Platform ad account ID (e.g. act_123 for Meta) }
33376
33435
  - { name: accountId, in: query, schema: { type: string }, description: Social account ID }
@@ -33465,7 +33524,7 @@ paths:
33465
33524
  required: [status, platform]
33466
33525
  properties:
33467
33526
  status: { type: string, enum: [active, paused] }
33468
- platform: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter] }
33527
+ platform: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter, openai] }
33469
33528
  responses:
33470
33529
  '200':
33471
33530
  description: Campaign status updated
@@ -33620,7 +33679,7 @@ paths:
33620
33679
  required: [platformCampaignId, platform]
33621
33680
  properties:
33622
33681
  platformCampaignId: { type: string }
33623
- platform: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter] }
33682
+ platform: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter, openai] }
33624
33683
  responses:
33625
33684
  '200':
33626
33685
  description: Per-campaign results
@@ -33894,7 +33953,7 @@ paths:
33894
33953
  type: object
33895
33954
  required: [platform]
33896
33955
  properties:
33897
- platform: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter] }
33956
+ platform: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter, openai] }
33898
33957
  budget:
33899
33958
  type: object
33900
33959
  description: Omit if not updating budget
@@ -33994,7 +34053,7 @@ paths:
33994
34053
  required: [status, platform]
33995
34054
  properties:
33996
34055
  status: { type: string, enum: [active, paused] }
33997
- platform: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter] }
34056
+ platform: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter, openai] }
33998
34057
  responses:
33999
34058
  '200':
34000
34059
  description: Ad set status updated
@@ -34033,7 +34092,7 @@ paths:
34033
34092
  - $ref: '#/components/parameters/PageParam'
34034
34093
  - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 100, default: 20 }, description: Campaigns per page }
34035
34094
  - { name: source, in: query, schema: { type: string, enum: [zernio, all], default: all }, description: "`all` (default) returns both Zernio-created ads and those discovered from the platform's ad manager — matches the web UI's default view. Pass `zernio` to restrict to isExternal=false only. Status is NOT filtered by default — use the `status` param for that." }
34036
- - { name: platform, in: query, schema: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter] } }
34095
+ - { name: platform, in: query, schema: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter, openai] } }
34037
34096
  - { name: status, in: query, schema: { $ref: '#/components/schemas/AdStatus' }, description: Filter by derived campaign status (post-aggregation) }
34038
34097
  - { name: adAccountId, in: query, schema: { type: string }, description: Platform ad account ID }
34039
34098
  - { name: accountId, in: query, schema: { type: string }, description: Social account ID }
@@ -34092,7 +34151,7 @@ paths:
34092
34151
  - { name: adAccountId, in: query, schema: { type: string }, description: "Optional platform-native ad account ID (e.g. Meta `act_…`, TikTok advertiser ID). Use when the connection wraps multiple platform ad accounts and the chart should show one only. Note: rows ingested before 2026-05-13 don't carry this column; the recurring 7-day re-sync repopulates them naturally." }
34093
34152
  - { name: fromDate, in: query, schema: { type: string, format: date }, description: "Inclusive start of metrics range (YYYY-MM-DD). Defaults to 90 days ago." }
34094
34153
  - { name: toDate, in: query, schema: { type: string, format: date }, description: "Inclusive end of metrics range (YYYY-MM-DD). Defaults to today. Max 730-day range." }
34095
- - { name: platform, in: query, schema: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter] }, description: Restrict to one platform. }
34154
+ - { name: platform, in: query, schema: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter, openai] }, description: Restrict to one platform. }
34096
34155
  responses:
34097
34156
  '200':
34098
34157
  description: Daily time series of aggregate metrics. Empty `rows` means the account has no ad activity in the range.
@@ -34185,8 +34244,9 @@ paths:
34185
34244
  - **Meta** (Facebook + Instagram): all fields supported.
34186
34245
  - **TikTok**: status, budget, targeting (via `/v2/adgroup/update/`), and creative
34187
34246
  (via `/v2/ad/update/` patch-style — `headline` is ignored, `body` becomes `ad_text`).
34188
- - **Pinterest / X / LinkedIn / Google**: status + budget only. Sending `targeting`
34189
- or `creative` returns 501 with code `unsupported_platform_operation`.
34247
+ - **Pinterest / X / LinkedIn / Google / OpenAI Ads**: status + budget only. Sending
34248
+ `targeting` or `creative` returns 501 with code `unsupported_platform_operation`.
34249
+ OpenAI Ads budget is lifetime-only (see `budget.type` below).
34190
34250
  security:
34191
34251
  - bearerAuth: []
34192
34252
  parameters:
@@ -34203,7 +34263,7 @@ paths:
34203
34263
  type: object
34204
34264
  properties:
34205
34265
  amount: { type: number, description: "Minimum varies by platform: TikTok=$20, Pinterest=$5, others=$1" }
34206
- type: { type: string, enum: [daily, lifetime] }
34266
+ type: { type: string, enum: [daily, lifetime], description: "OpenAI Ads accepts lifetime only; sending daily returns 422." }
34207
34267
  targeting:
34208
34268
  type: object
34209
34269
  description: |
@@ -34261,7 +34321,7 @@ paths:
34261
34321
  tags: ["Ad Campaigns"]
34262
34322
  x-platforms: ["meta", "google", "tiktok", "linkedin", "pinterest", "x"]
34263
34323
  summary: Cancel an ad
34264
- description: Cancels the ad on the platform and marks it as cancelled in the database. The ad is preserved for history.
34324
+ description: Cancels 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).
34265
34325
  security:
34266
34326
  - bearerAuth: []
34267
34327
  parameters:
@@ -35933,9 +35993,9 @@ paths:
35933
35993
  summary: Create standalone ad
35934
35994
  description: >-
35935
35995
  Creates a paid ad with custom creative across Meta, Google Ads,
35936
- Pinterest, TikTok, X/Twitter, and LinkedIn. Supports three
35937
- mutually-exclusive request shapes selected by the body, a legacy
35938
- single-creative shape (all platforms, default), a Meta-only
35996
+ Pinterest, TikTok, X/Twitter, LinkedIn, and OpenAI Ads (ChatGPT Ads).
35997
+ Supports three mutually-exclusive request shapes selected by the body,
35998
+ a legacy single-creative shape (all platforms, default), a Meta-only
35939
35999
  multi-creative shape via the creatives array (one ad set with N ads
35940
36000
  sharing budget and targeting), and a Meta-only attach shape via adSetId
35941
36001
  (adds one new ad to an existing ad set). Per-platform required fields,
@@ -36014,6 +36074,9 @@ paths:
36014
36074
  - `engagement`, `traffic`, `awareness` and `video_views` create standalone Direct Sponsored Content ads. `traffic` requires `linkUrl`; `video_views` requires `video`.
36015
36075
  - `job_applicants` requires a `platformSpecificData.jobs` creative.
36016
36076
  - For `lead_generation` or `conversions` on LinkedIn, or to promote an existing post, use POST /v1/ads/boost.
36077
+
36078
+ **OpenAI Ads**
36079
+ - Only `traffic`, `awareness`, and `conversions` are supported (other goals return 400). Maps to OpenAI's `bidding_type` (clicks, impressions, conversions respectively). `conversions` requires an active conversion event setting on the account; create a tracking tag with `defaultEventType` via the tracking-tags API (`POST /v1/accounts/{accountId}/tracking-tags`), or configure a conversion event in OpenAI Ads Manager, or the request returns 422.
36017
36080
  optimizationGoal: { type: string, description: "Meta only. Explicit ad-set `optimization_goal` (e.g. `LANDING_PAGE_VIEWS`, `LINK_CLICKS`, `REACH`, `IMPRESSIONS`, `OFFSITE_CONVERSIONS`, `THRUPLAY`, `LEAD_GENERATION`). Overrides the default derived from `goal` (e.g. `traffic` defaults to `LINK_CLICKS`). Forwarded verbatim to Meta, which validates compatibility with the campaign objective and rejects incompatible combinations." }
36018
36081
  billingEvent: { type: string, description: "Meta only. Explicit ad-set `billing_event`. Defaults to `IMPRESSIONS`. Forwarded verbatim to Meta, which validates compatibility with the optimization goal." }
36019
36082
  buyingType: { type: string, enum: [AUCTION, RESERVED], description: "Meta only. RESERVED = Reach & Frequency: requires `rfPredictionId` (a RESERVED prediction from /v1/ads/rf-predictions + /reserve). Budget, schedule and pricing come from the reservation, so budgetAmount/budgetType are not required and bid fields are ignored. Only the plain single-ad shape (no creatives[], adSetId, existingCampaignId or dynamicCreative)." }
@@ -36025,8 +36088,8 @@ paths:
36025
36088
  validateOnly:
36026
36089
  type: boolean
36027
36090
  description: 'Meta only, single standalone shape only (no creatives[], adSetId, or RESERVED). Dry-run: each node runs Meta''s execution_options validate_only and NOTHING is created or persisted. Children need real parents, so a fresh tree validates the campaign + creative (the ad set needs its campaign to exist — pass existingCampaignId to validate it too; the ad itself is never validatable pre-create). A Meta validation failure returns the 400 verbatim; success returns 200 with per-node results instead of an ad.'
36028
- budgetAmount: { type: number, description: "Required on legacy + multi-creative shapes. Inherited on attach." }
36029
- budgetType: { type: string, enum: [daily, lifetime], description: "Required on legacy + multi-creative shapes. Inherited on attach." }
36091
+ budgetAmount: { type: number, description: "Required on legacy + multi-creative shapes. Inherited on attach. OpenAI Ads requires a $1 minimum (its budget is lifetime-only, see budgetType)." }
36092
+ budgetType: { type: string, enum: [daily, lifetime], description: "Required on legacy + multi-creative 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." }
36030
36093
  status:
36031
36094
  type: string
36032
36095
  enum: [ACTIVE, PAUSED]
@@ -36045,14 +36108,14 @@ paths:
36045
36108
  Meta requires the budget at exactly one level, never both. Non-Meta platforms ignore
36046
36109
  this field. Ignored on the attach shape (`adSetId`), which inherits the existing budget.
36047
36110
  currency: { type: string }
36048
- headline: { type: string, description: "Required for Meta, Google, Pinterest, and LinkedIn on legacy + attach shapes (skip for multi-creative — use `creatives[].headline`). Ignored for TikTok and X/Twitter. Max: Meta=255, Google=30, Pinterest=100, LinkedIn=400. On LinkedIn this is the ad's headline (the bold text on the creative); for traffic ads it's the link card title." }
36111
+ headline: { type: string, description: "Required for Meta, Google, Pinterest, LinkedIn, and OpenAI Ads on legacy + attach shapes (skip for multi-creative — use `creatives[].headline`). Ignored for TikTok and X/Twitter. Max: Meta=255, Google=30, Pinterest=100, LinkedIn=400, OpenAI=50 (min 3). On LinkedIn this is the ad's headline (the bold text on the creative); for traffic ads it's the link card title. On OpenAI Ads this is the chat card's title." }
36049
36112
  longHeadline: { type: string, maxLength: 90, description: "Google Display only — defaults to `headline` if omitted. On LinkedIn, reused as the optional secondary description text on traffic (link) ads; omitted if not provided." }
36050
- body: { type: string, description: "Required on legacy + attach shapes. For X/Twitter this is the tweet text (max 280 chars including a ~24-char URL when `linkUrl` is set). On LinkedIn this is the post commentary (the intro text shown above the ad). Max: Google=90, Pinterest=500." }
36113
+ body: { type: string, description: "Required on legacy + attach shapes. For X/Twitter this is the tweet text (max 280 chars including a ~24-char URL when `linkUrl` is set). On LinkedIn this is the post commentary (the intro text shown above the ad). On OpenAI Ads this is the chat card's body text. Max: Google=90, Pinterest=500, OpenAI=100." }
36051
36114
  description: { type: string, maxLength: 255, description: "Meta only (facebook/instagram). Link description — the secondary text shown below the headline (Meta's link_data.description; on video creatives mapped to video_data.link_description). When omitted, Meta auto-pulls the destination URL's OpenGraph description. Applies on legacy, attach, and placementAssets shapes; for multi-creative use creatives[].description (this field is the shared fallback). For multi-text variations use dynamicCreative.descriptions instead." }
36052
36115
  callToAction: { type: string, enum: [LEARN_MORE, SHOP_NOW, SIGN_UP, BOOK_TRAVEL, CONTACT_US, DOWNLOAD, GET_OFFER, GET_QUOTE, SUBSCRIBE, WATCH_MORE, ADD_TO_CART, APPLY_NOW, BOOK_NOW, BUY_TICKETS, DONATE, DONATE_NOW, GET_DIRECTIONS, GET_SHOWTIMES, LISTEN_NOW, ORDER_NOW, PLAY_GAME, REQUEST_TIME, SEE_MENU, START_ORDER, INSTALL_MOBILE_APP, USE_APP, REGISTER, JOIN, ATTEND, REQUEST_DEMO, VIEW_QUOTE, APPLY, SEE_MORE, BUY_NOW], description: "Required on legacy + attach shapes for Meta. Honoured on TikTok (passes through to the Spark Ad creative's `call_to_action`) and on LinkedIn (the CTA button on the ad; defaults to LEARN_MORE when `linkUrl` is set). LinkedIn accepts: LEARN_MORE, SIGN_UP, DOWNLOAD, SUBSCRIBE, REGISTER, JOIN, ATTEND, REQUEST_DEMO, VIEW_QUOTE, APPLY, SEE_MORE, SHOP_NOW, BUY_NOW. Ignored by Google, Pinterest, and X/Twitter." }
36053
- linkUrl: { type: string, format: uri, description: "Required on legacy + attach shapes (skip for multi-creative). On LinkedIn it's the ad's destination URL; required for `traffic` ads, optional for `engagement` / `awareness`. NOT required when `goal` is `lead_generation` (the ad opens a Lead Gen form instead of a destination). On LinkedIn, `imageUrl` + `linkUrl` publishes an ARTICLE-content creative; this is LinkedIn's article ad format, with the image as thumbnail and `longHeadline` as description." }
36116
+ linkUrl: { type: string, format: uri, description: "Required on legacy + attach shapes (skip for multi-creative). On LinkedIn it's the ad's destination URL; required for `traffic` ads, optional for `engagement` / `awareness`. NOT required when `goal` is `lead_generation` (the ad opens a Lead Gen form instead of a destination). On LinkedIn, `imageUrl` + `linkUrl` publishes an ARTICLE-content creative; this is LinkedIn's article ad format, with the image as thumbnail and `longHeadline` as description. Required for OpenAI Ads (the chat card's target_url)." }
36054
36117
  leadGenFormId: { type: string, description: "Meta Lead Gen forms only (facebook/instagram). The leadgen_forms ID to attach to the ad's creative — create one via POST /v1/ads/lead-forms. REQUIRED when `goal` is `lead_generation`, and on every ATTACH (`adSetId`) call that targets a lead ad set (the form attaches per-ad; Meta rejects a formless ad in a lead ad set). Ignored otherwise. The ad set's promoted_object.page_id + LEAD_GENERATION optimization + destination_type ON_AD are derived automatically from the goal. Both `placementAssets` (per-placement creative) and `dynamicCreative` (multi-text / multi-asset pool, e.g. multiple headlines and primary texts) ARE supported on instant-form lead ads — the form is attached for you, and for `dynamicCreative` the ad set is created as a Dynamic Creative ad set automatically (Meta requires that for any multi-text feed; there is no non-DCO multi-text path). Send a single `imageUrls` entry plus your text variations to get Meta's \"Multiple Text Options\" behavior on a lead ad." }
36055
- imageUrl: { type: string, format: uri, description: "Image creative for Meta/Google/Pinterest/LinkedIn on legacy + attach shapes (mutually exclusive with `video`). Required for LinkedIn ads unless `video` is set. Not required for Google Search campaigns. For TikTok, this field carries the VIDEO URL (the TikTok ads endpoint is video-only; the field retains the `imageUrl` name for cross-platform consistency). Ignored for X/Twitter. For Google Display, treated as the landscape image (alias of `images.landscape`); supply `images.square` alongside or the request is rejected. For LinkedIn the image is uploaded to LinkedIn under the authoring Company Page (see `organizationId`); recommended ratio 1.91:1 (e.g. 1200×627)." }
36118
+ imageUrl: { type: string, format: uri, description: "Image creative for Meta/Google/Pinterest/LinkedIn on legacy + attach shapes (mutually exclusive with `video`). Required for LinkedIn ads unless `video` is set. Not required for Google Search campaigns. For TikTok, this field carries the VIDEO URL (the TikTok ads endpoint is video-only; the field retains the `imageUrl` name for cross-platform consistency). Ignored for X/Twitter. For Google Display, treated as the landscape image (alias of `images.landscape`); supply `images.square` alongside or the request is rejected. For LinkedIn the image is uploaded to LinkedIn under the authoring Company Page (see `organizationId`); recommended ratio 1.91:1 (e.g. 1200×627). Required for OpenAI Ads (uploaded as the chat card's image; OpenAI has no video ad format)." }
36056
36119
  images:
36057
36120
  type: object
36058
36121
  description: "Google Display (Responsive Display Ads) only. Google RDA requires both a landscape (1.91:1) and a square (1:1) marketing image; sending only one is rejected upstream as 'Too few.' (NOT_ENOUGH_*_MARKETING_IMAGE_ASSET). Supply both URLs here. Either this field or the legacy `imageUrl` can provide the landscape, but `square` has no legacy counterpart so it must be set here for Display."
@@ -36160,7 +36223,7 @@ paths:
36160
36223
  Both forms are equivalent; use whichever your integration already builds.
36161
36224
  allOf:
36162
36225
  - $ref: '#/components/schemas/TargetingSpec'
36163
- countries: { type: array, items: { type: string }, description: "ISO 3166-1 alpha-2 country codes (e.g. ['NL']). Defaults to ['US'] when no other geo targeting (flat or nested `targeting`) is provided. (LinkedIn currently honours country-level targeting only.)" }
36226
+ countries: { type: array, items: { type: string }, description: "ISO 3166-1 alpha-2 country codes (e.g. ['NL']). Defaults to ['US'] when no other geo targeting (flat or nested `targeting`) is provided. (LinkedIn and OpenAI Ads currently honour country-level targeting only; any other targeting field returns 400 for OpenAI Ads.)" }
36164
36227
  cities:
36165
36228
  type: array
36166
36229
  description: |
@@ -37810,6 +37873,7 @@ paths:
37810
37873
  - Google Ads (`googleads`) via Data Manager API `ingestEvents`
37811
37874
  - LinkedIn (`linkedinads`) via `/rest/conversionEvents`
37812
37875
  - TikTok (`tiktokads`) via the Offline Events API `/offline/batch/` — OFFLINE conversions only
37876
+ - OpenAI Ads (`openaiads`) via its Conversions API (a separate host, `bzr.openai.com`)
37813
37877
 
37814
37878
  `destinationId` semantics differ per platform:
37815
37879
 
@@ -37817,11 +37881,16 @@ paths:
37817
37881
  - Google: conversion action resource name, e.g. `customers/1234567890/conversionActions/987654321`
37818
37882
  - LinkedIn: conversion rule ID or URN, e.g. `104012` or `urn:lla:llaPartnerConversion:104012`
37819
37883
  - TikTok: Offline Event Set ID, e.g. `7057103914977558530`
37884
+ - OpenAI Ads: pixel wire id (numeric `pixel_id`, distinct from the internal pixel id), as returned by `GET /v1/accounts/{accountId}/conversion-destinations`
37820
37885
 
37821
37886
  TikTok notes: this path sends OFFLINE conversions (in-store / CRM / call-center), not web-pixel
37822
37887
  events. Each event must carry an email or phone (TikTok requires at least one). The connected
37823
37888
  TikTok ads account must have granted the Offline Events permission; older grants must reconnect.
37824
37889
 
37890
+ OpenAI Ads notes: requires a tracking tag (pixel) to already exist on the account — returns 422
37891
+ with code `TRACKING_TAG_REQUIRED` if `POST /v1/accounts/{accountId}/tracking-tags` hasn't been
37892
+ called yet.
37893
+
37825
37894
  Callers can list valid destinations via `GET /v1/accounts/{accountId}/conversion-destinations`.
37826
37895
 
37827
37896
  All PII (email, phone, names, external IDs) is hashed with SHA-256 server-side per each
@@ -37834,7 +37903,9 @@ paths:
37834
37903
 
37835
37904
  Batching is handled automatically. Meta caps at 1000 events per request and rejects the
37836
37905
  entire batch if any event is malformed. Google caps at 2000. LinkedIn caps at 5000 and is
37837
- also all-or-nothing per chunk.
37906
+ also all-or-nothing per chunk. OpenAI Ads caps at 1000 per request; larger submissions are
37907
+ split into 1000-event chunks, each all-or-nothing (a malformed event fails every event in
37908
+ that chunk, not the whole request).
37838
37909
 
37839
37910
  Dedup: pass a stable `eventId` on every event. Meta and LinkedIn use it to dedupe against
37840
37911
  browser-side pixel/Insight Tag events; Google maps it to `transactionId`.
@@ -37844,6 +37915,7 @@ paths:
37844
37915
  - Meta: free-form. Standard names (Purchase, Lead, ...) match Meta's built-in events; custom strings are accepted.
37845
37916
  - Google: ignored. The conversion action's category determines the event type. Send the standard name closest to your action for documentation, but the platform will not branch on it.
37846
37917
  - LinkedIn: ignored. The conversion rule's `type` (LEAD, PURCHASE, etc.) is locked to the destination at rule-creation time. Send the standard name for documentation; LinkedIn does not branch on it.
37918
+ - OpenAI Ads: a fixed subset of standard names (Purchase, Lead, AddToCart, ViewContent, InitiateCheckout, CompleteRegistration, Subscribe, StartTrial, Schedule) maps 1:1 onto OpenAI's own event-type enum; any other standard name or custom string is sent as `type: custom` with the name preserved.
37847
37919
  security:
37848
37920
  - bearerAuth: []
37849
37921
  requestBody:
@@ -37856,21 +37928,22 @@ paths:
37856
37928
  properties:
37857
37929
  accountId:
37858
37930
  type: string
37859
- description: SocialAccount ID (metaads, googleads, linkedinads, or tiktokads).
37931
+ description: SocialAccount ID (metaads, googleads, linkedinads, tiktokads, or openaiads).
37860
37932
  destinationId:
37861
37933
  type: string
37862
37934
  description: |
37863
37935
  Platform destination identifier. For Meta, the pixel/dataset
37864
37936
  ID. For Google, the conversion action resource name. For
37865
37937
  LinkedIn, the conversion rule ID or full
37866
- `urn:lla:llaPartnerConversion:{id}` URN.
37938
+ `urn:lla:llaPartnerConversion:{id}` URN. For OpenAI Ads, the
37939
+ pixel wire id.
37867
37940
  events:
37868
37941
  type: array
37869
37942
  minItems: 1
37870
37943
  items: { $ref: '#/components/schemas/ConversionEvent' }
37871
37944
  testCode:
37872
37945
  type: string
37873
- description: Meta `test_event_code` passthrough. Ignored by Google and LinkedIn.
37946
+ description: Meta `test_event_code` passthrough. Ignored by Google, LinkedIn, and OpenAI Ads.
37874
37947
  consent:
37875
37948
  type: object
37876
37949
  description: |
@@ -37891,13 +37964,14 @@ paths:
37891
37964
  partial failure. For Meta, a batch is all-or-nothing (either every
37892
37965
  event in a chunk succeeds, or every event in the chunk is listed
37893
37966
  in failures). For Google, the API returns success/failure at the
37894
- request level only.
37967
+ request level only. For OpenAI Ads, each 1000-event chunk is
37968
+ all-or-nothing, same as Meta.
37895
37969
  content:
37896
37970
  application/json:
37897
37971
  schema:
37898
37972
  type: object
37899
37973
  properties:
37900
- platform: { type: string, enum: [metaads, googleads, linkedinads, tiktokads] }
37974
+ platform: { type: string, enum: [metaads, googleads, linkedinads, tiktokads, openaiads] }
37901
37975
  eventsReceived: { type: integer, description: Events accepted by the platform. }
37902
37976
  eventsFailed: { type: integer, description: Events rejected (see failures). }
37903
37977
  failures:
@@ -37914,7 +37988,8 @@ paths:
37914
37988
  description: |
37915
37989
  Platform trace ID for debugging. fbtrace_id for Meta,
37916
37990
  requestId for Google. Absent for LinkedIn (LinkedIn's
37917
- conversionEvents endpoint does not surface a trace ID).
37991
+ conversionEvents endpoint does not surface a trace ID)
37992
+ and OpenAI Ads (no trace ID surfaced).
37918
37993
  '400':
37919
37994
  description: Invalid body (missing accountId/destinationId/events, malformed event shape).
37920
37995
  '401': { $ref: '#/components/responses/Unauthorized' }
@@ -37924,6 +37999,8 @@ paths:
37924
37999
  OR (for LinkedIn) the connected account lacks the `rw_conversions` scope and must be reconnected.
37925
38000
  '404':
37926
38001
  description: Account not found or not accessible.
38002
+ '422':
38003
+ description: 'OpenAI Ads only: no tracking tag (pixel) exists yet for this account. Code `TRACKING_TAG_REQUIRED` — create one via `POST /v1/accounts/{accountId}/tracking-tags` first.'
37927
38004
  '429':
37928
38005
  description: |
37929
38006
  LinkedIn token-level rate limit hit (600 requests/min, 300k/day
@@ -38058,15 +38135,15 @@ paths:
38058
38135
  x-platforms: ["meta", "google", "tiktok", "linkedin"]
38059
38136
  summary: List conversion destinations
38060
38137
  description: |
38061
- Returns the list of pixels (Meta), conversion actions (Google), or
38062
- conversion rules (LinkedIn) accessible to the connected ads account.
38063
- Use the returned `id` as `destinationId` when posting to
38064
- `POST /v1/ads/conversions`.
38138
+ Returns the list of pixels (Meta), conversion actions (Google),
38139
+ conversion rules (LinkedIn), or pixels (OpenAI Ads) accessible to the
38140
+ connected ads account. Use the returned `id` as `destinationId` when
38141
+ posting to `POST /v1/ads/conversions`.
38065
38142
 
38066
38143
  For Google and LinkedIn, each destination's `type` reflects the
38067
38144
  conversion type (PURCHASE, LEAD, SIGN_UP, etc.) — the event type is
38068
- locked to the destination. For Meta, `type` is absent: pixels accept
38069
- any event name per request.
38145
+ locked to the destination. For Meta and OpenAI Ads, `type` is absent:
38146
+ pixels accept any event name per request.
38070
38147
 
38071
38148
  For LinkedIn, destinations are returned across every sponsored ad
38072
38149
  account the connected token can access; the `adAccountId` field on
@@ -38079,7 +38156,7 @@ paths:
38079
38156
  in: path
38080
38157
  required: true
38081
38158
  schema: { type: string }
38082
- description: SocialAccount ID (metaads, googleads, linkedinads, or tiktokads).
38159
+ description: SocialAccount ID (metaads, googleads, linkedinads, tiktokads, or openaiads).
38083
38160
  responses:
38084
38161
  '200':
38085
38162
  description: Destinations listed
@@ -38088,7 +38165,7 @@ paths:
38088
38165
  schema:
38089
38166
  type: object
38090
38167
  properties:
38091
- platform: { type: string, enum: [metaads, googleads, linkedinads, tiktokads] }
38168
+ platform: { type: string, enum: [metaads, googleads, linkedinads, tiktokads, openaiads] }
38092
38169
  destinations:
38093
38170
  type: array
38094
38171
  items:
@@ -38099,7 +38176,8 @@ paths:
38099
38176
  description: |
38100
38177
  Destination identifier. Meta: pixel ID. Google:
38101
38178
  conversion action resource name. LinkedIn:
38102
- numeric conversion rule ID.
38179
+ numeric conversion rule ID. OpenAI Ads: pixel wire
38180
+ id.
38103
38181
  name: { type: string }
38104
38182
  type:
38105
38183
  type: string
@@ -38134,7 +38212,9 @@ paths:
38134
38212
  description: |
38135
38213
  Create a new conversion destination on the platform. Supported for
38136
38214
  LinkedIn (conversion rule) and Google Ads (conversion action). Meta
38137
- manages destinations in its own UI and returns 405.
38215
+ and OpenAI Ads pixels are created via their own tracking-tags flow
38216
+ instead (`POST /v1/accounts/{accountId}/tracking-tags`); this endpoint
38217
+ returns 405 for both.
38138
38218
 
38139
38219
  **LinkedIn:** creation is NOT idempotent. A retry creates a second
38140
38220
  destination. Deduplicate before retrying.
@@ -39041,22 +39121,25 @@ paths:
39041
39121
  x-platforms: ["meta"]
39042
39122
  summary: List tracking tags
39043
39123
  description: |
39044
- Returns the tracking tags (Meta Pixels) the connected ads account can
39045
- see. Pass `?adAccountId=act_...` to scope the list to a single ad
39046
- account; omit it to list every pixel reachable by the token (the name
39047
- is then suffixed with the ad account it was discovered on, for
39048
- disambiguation). The list view omits `code` — call `getTrackingTag` for
39049
- the install snippet and full detail.
39124
+ Returns the tracking tags (Meta Pixels, or OpenAI Ads pixels) the
39125
+ connected ads account can see. Pass `?adAccountId=act_...` (Meta only)
39126
+ to scope the list to a single ad account; omit it to list every pixel
39127
+ reachable by the token (the name is then suffixed with the ad account
39128
+ it was discovered on, for disambiguation). The list view omits `code`
39129
+ — call `getTrackingTag` for the install snippet and full detail (Meta
39130
+ only; OpenAI Ads has no get-by-id endpoint).
39050
39131
 
39051
- Meta only today (platform `metaads`); other platforms return 405. The
39052
- `accountId` must be the Meta *ads* SocialAccount created by the Ads
39053
- add-on connect flow, not a Facebook/Instagram posting account. Get your
39054
- `act_...` ids from `GET /v1/ads/accounts`.
39132
+ Meta (platform `metaads`) and OpenAI Ads (platform `openaiads`); other
39133
+ platforms return 405. The `accountId` must be the ads SocialAccount
39134
+ created by the Ads add-on connect flow (Meta) or the OpenAI Ads
39135
+ connect flow, not a Facebook/Instagram posting account. Get your Meta
39136
+ `act_...` ids from `GET /v1/ads/accounts`; `adAccountId` is ignored for
39137
+ OpenAI Ads (one API key maps to exactly one ad account).
39055
39138
  security:
39056
39139
  - bearerAuth: []
39057
39140
  parameters:
39058
- - { name: accountId, in: path, required: true, schema: { type: string }, description: 'Meta ads SocialAccount id (platform `metaads`).' }
39059
- - { name: adAccountId, in: query, required: false, schema: { type: string }, description: 'Optional. Scope to one ad account, e.g. `act_123456789`.' }
39141
+ - { name: accountId, in: path, required: true, schema: { type: string }, description: 'Ads SocialAccount id (platform `metaads` or `openaiads`).' }
39142
+ - { name: adAccountId, in: query, required: false, schema: { type: string }, description: 'Optional, Meta only. Scope to one ad account, e.g. `act_123456789`. Ignored for OpenAI Ads.' }
39060
39143
  responses:
39061
39144
  '200':
39062
39145
  description: Tracking tags listed
@@ -39065,7 +39148,7 @@ paths:
39065
39148
  schema:
39066
39149
  type: object
39067
39150
  properties:
39068
- platform: { type: string, enum: [metaads] }
39151
+ platform: { type: string, enum: [metaads, openaiads] }
39069
39152
  tags:
39070
39153
  type: array
39071
39154
  items: { $ref: '#/components/schemas/TrackingTag' }
@@ -39081,23 +39164,37 @@ paths:
39081
39164
  x-platforms: ["meta"]
39082
39165
  summary: Create a tracking tag
39083
39166
  description: |
39084
- Creates a Meta Pixel on the given ad account (`POST /act_{id}/adspixels`
39167
+ Meta: creates a Meta Pixel on the given ad account (`POST /act_{id}/adspixels`
39085
39168
  — `name` is the only input). Returns the created tag including its
39086
39169
  install `code`. The pixel is owned by the Business Manager that owns the
39087
39170
  ad account; a pixel created on a personal (non-BM) ad account ends up
39088
39171
  with `ownerBusinessId: null` and can't be shared with other ad accounts.
39089
39172
 
39090
- Creating a pixel does NOT install it — install the returned `code`
39173
+ Creating a Meta pixel does NOT install it — install the returned `code`
39091
39174
  snippet on the site, or send events server-side via
39092
39175
  `POST /v1/ads/conversions`. The check `installed` is derived from
39093
39176
  `lastFiredTime`.
39094
39177
 
39095
- NOT idempotent: each call creates a new pixel. Do not retry blindly on
39096
- timeout. Meta only (platform `metaads`); other platforms return 405.
39178
+ OpenAI Ads: creates an OpenAI pixel AND provisions a Conversions API
39179
+ key for it in the same call (`adAccountId` is required by this
39180
+ endpoint but ignored — one API key maps to exactly one ad account, so
39181
+ there's nothing to select). Returns 422 (`FEATURE_NOT_AVAILABLE`) if
39182
+ the ad account isn't enabled for pixel management; contact your OpenAI
39183
+ partner representative to enable it. There is no delete API for
39184
+ OpenAI pixels. If the pixel is created but the Conversions API key
39185
+ provisioning then fails, the pixel is left live on OpenAI (it cannot
39186
+ be cleaned up) and the error message names the surviving pixel id and
39187
+ warns against retrying, since a retry would create a second, orphaned
39188
+ pixel.
39189
+
39190
+ NOT idempotent on either platform: each call creates a new pixel (and,
39191
+ for OpenAI, a new Conversions API key). Do not retry blindly on
39192
+ timeout. Meta (platform `metaads`) and OpenAI Ads (platform
39193
+ `openaiads`); other platforms return 405.
39097
39194
  security:
39098
39195
  - bearerAuth: []
39099
39196
  parameters:
39100
- - { name: accountId, in: path, required: true, schema: { type: string }, description: 'Meta ads SocialAccount id (platform `metaads`).' }
39197
+ - { name: accountId, in: path, required: true, schema: { type: string }, description: 'Ads SocialAccount id (platform `metaads` or `openaiads`).' }
39101
39198
  requestBody:
39102
39199
  required: true
39103
39200
  content:
@@ -39106,7 +39203,7 @@ paths:
39106
39203
  type: object
39107
39204
  required: [adAccountId, name]
39108
39205
  properties:
39109
- adAccountId: { type: string, description: 'Meta ad account id, e.g. `act_123456789`.' }
39206
+ adAccountId: { type: string, description: 'Meta ad account id, e.g. `act_123456789`. Required by this endpoint but ignored for OpenAI Ads.' }
39110
39207
  name: { type: string, minLength: 1, maxLength: 200 }
39111
39208
  responses:
39112
39209
  '201':
@@ -39116,13 +39213,14 @@ paths:
39116
39213
  schema:
39117
39214
  type: object
39118
39215
  properties:
39119
- platform: { type: string, enum: [metaads] }
39216
+ platform: { type: string, enum: [metaads, openaiads] }
39120
39217
  tag: { $ref: '#/components/schemas/TrackingTag' }
39121
39218
  '400': { description: 'Invalid body, invalid `adAccountId`, over the per-business pixel cap, or ad account not in a Business Manager.' }
39122
39219
  '401': { $ref: '#/components/responses/Unauthorized' }
39123
39220
  '403': { description: 'Ads access required (Ads add-on on legacy plans, included on usage-based plans), or the Meta token lacks ads permissions (reconnect required).' }
39124
39221
  '404': { description: Account not found or not accessible. }
39125
39222
  '405': { description: Platform does not support creating tracking tags. }
39223
+ '422': { description: 'OpenAI Ads only: the ad account is not enabled for pixel management. Contact your OpenAI partner representative.' }
39126
39224
 
39127
39225
  /v1/accounts/{accountId}/tracking-tags/{tagId}:
39128
39226
  get:
@@ -39133,7 +39231,9 @@ paths:
39133
39231
  description: |
39134
39232
  Returns the full tag record including the base-code `code` snippet,
39135
39233
  `lastFiredTime`, `ownerBusinessId`, `isUnavailable`, etc. Meta only
39136
- (platform `metaads`); other platforms return 405.
39234
+ (platform `metaads`); other platforms return 405. OpenAI Ads has no
39235
+ get-by-id endpoint, so it 405s here too — use
39236
+ `GET /v1/accounts/{accountId}/tracking-tags` (list) instead.
39137
39237
  security:
39138
39238
  - bearerAuth: []
39139
39239
  parameters:
@@ -70,7 +70,7 @@ describe 'AdCampaignsApi' do
70
70
 
71
71
  # unit tests for create_standalone_ad
72
72
  # Create standalone ad
73
- # Creates a paid ad with custom creative across Meta, Google Ads, Pinterest, TikTok, X/Twitter, and LinkedIn. Supports three mutually-exclusive request shapes selected by the body, a legacy single-creative shape (all platforms, default), a Meta-only multi-creative shape via the creatives array (one ad set with N ads sharing budget and targeting), and a Meta-only attach shape via adSetId (adds one new ad to an existing ad set). 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.
73
+ # Creates a paid ad with custom creative across Meta, Google Ads, Pinterest, TikTok, X/Twitter, LinkedIn, and OpenAI Ads (ChatGPT Ads). Supports three mutually-exclusive request shapes selected by the body, a legacy single-creative shape (all platforms, default), a Meta-only multi-creative shape via the creatives array (one ad set with N ads sharing budget and targeting), and a Meta-only attach shape via adSetId (adds one new ad to an existing ad set). 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.
74
74
  # @param create_standalone_ad_request
75
75
  # @param [Hash] opts the optional parameters
76
76
  # @option opts [String] :idempotency_key Optional client-generated unique key (e.g. a UUID) that makes create retries safe. Same key + same body replays the original response; same key + different body → 422; key still processing → 409.
@@ -83,7 +83,7 @@ describe 'AdCampaignsApi' do
83
83
 
84
84
  # unit tests for delete_ad
85
85
  # Cancel an ad
86
- # Cancels the ad on the platform and marks it as cancelled in the database. The ad is preserved for history.
86
+ # Cancels 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).
87
87
  # @param ad_id
88
88
  # @param [Hash] opts the optional parameters
89
89
  # @return [DeleteAccountGroup200Response]
@@ -260,7 +260,7 @@ describe 'AdCampaignsApi' do
260
260
 
261
261
  # unit tests for update_ad
262
262
  # Update ad
263
- # Patch one or more fields on an ad. Status, budget, targeting, and creative changes are propagated to the platform. Per-platform support: - **Meta** (Facebook + Instagram): all fields supported. - **TikTok**: status, budget, targeting (via `/v2/adgroup/update/`), and creative (via `/v2/ad/update/` patch-style — `headline` is ignored, `body` becomes `ad_text`). - **Pinterest / X / LinkedIn / Google**: status + budget only. Sending `targeting` or `creative` returns 501 with code `unsupported_platform_operation`.
263
+ # Patch one or more fields on an ad. Status, budget, targeting, and creative changes are propagated to the platform. Per-platform support: - **Meta** (Facebook + Instagram): all fields supported. - **TikTok**: status, budget, targeting (via `/v2/adgroup/update/`), and creative (via `/v2/ad/update/` patch-style — `headline` is ignored, `body` becomes `ad_text`). - **Pinterest / X / LinkedIn / Google / OpenAI Ads**: status + budget only. Sending `targeting` or `creative` returns 501 with code `unsupported_platform_operation`. OpenAI Ads budget is lifetime-only (see `budget.type` below).
264
264
  # @param ad_id
265
265
  # @param update_ad_request
266
266
  # @param [Hash] opts the optional parameters