zernio-sdk 0.0.552 → 0.0.554

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 (65) 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/docs/UpdateAdSetRequest.md +3 -3
  18. data/lib/zernio-sdk/api/ad_campaigns_api.rb +10 -10
  19. data/lib/zernio-sdk/api/connect_api.rb +68 -0
  20. data/lib/zernio-sdk/api/conversions_api.rb +8 -8
  21. data/lib/zernio-sdk/api/tracking_tags_api.rb +18 -18
  22. data/lib/zernio-sdk/models/account_with_follower_stats.rb +2 -2
  23. data/lib/zernio-sdk/models/ad.rb +2 -2
  24. data/lib/zernio-sdk/models/ad_campaign.rb +2 -2
  25. data/lib/zernio-sdk/models/ad_tree_campaign.rb +2 -2
  26. data/lib/zernio-sdk/models/bulk_update_ad_campaign_status_request_campaigns_inner.rb +2 -2
  27. data/lib/zernio-sdk/models/connect_open_ai_ads_credentials200_response.rb +165 -0
  28. data/lib/zernio-sdk/models/connect_open_ai_ads_credentials_request.rb +212 -0
  29. data/lib/zernio-sdk/models/conversion_event.rb +1 -1
  30. data/lib/zernio-sdk/models/create_standalone_ad_request.rb +8 -8
  31. data/lib/zernio-sdk/models/create_tracking_tag201_response.rb +2 -2
  32. data/lib/zernio-sdk/models/create_tracking_tag_request.rb +1 -1
  33. data/lib/zernio-sdk/models/get_tracking_tag200_response.rb +190 -0
  34. data/lib/zernio-sdk/models/list_conversion_destinations200_response.rb +2 -2
  35. data/lib/zernio-sdk/models/list_conversion_destinations200_response_destinations_inner.rb +1 -1
  36. data/lib/zernio-sdk/models/list_tracking_tags200_response.rb +2 -2
  37. data/lib/zernio-sdk/models/send_conversions200_response.rb +3 -3
  38. data/lib/zernio-sdk/models/send_conversions_request.rb +3 -3
  39. data/lib/zernio-sdk/models/social_account.rb +2 -2
  40. data/lib/zernio-sdk/models/update_ad_campaign_status_request.rb +2 -2
  41. data/lib/zernio-sdk/models/update_ad_request_budget.rb +1 -0
  42. data/lib/zernio-sdk/models/update_ad_set_request.rb +5 -5
  43. data/lib/zernio-sdk/version.rb +1 -1
  44. data/lib/zernio-sdk.rb +3 -0
  45. data/openapi.yaml +176 -71
  46. data/spec/api/ad_campaigns_api_spec.rb +3 -3
  47. data/spec/api/connect_api_spec.rb +12 -0
  48. data/spec/api/conversions_api_spec.rb +4 -4
  49. data/spec/api/tracking_tags_api_spec.rb +8 -8
  50. data/spec/models/account_with_follower_stats_spec.rb +1 -1
  51. data/spec/models/ad_campaign_spec.rb +1 -1
  52. data/spec/models/ad_spec.rb +1 -1
  53. data/spec/models/ad_tree_campaign_spec.rb +1 -1
  54. data/spec/models/bulk_update_ad_campaign_status_request_campaigns_inner_spec.rb +1 -1
  55. data/spec/models/connect_open_ai_ads_credentials200_response_spec.rb +48 -0
  56. data/spec/models/connect_open_ai_ads_credentials_request_spec.rb +54 -0
  57. data/spec/models/create_tracking_tag201_response_spec.rb +1 -1
  58. data/spec/models/get_tracking_tag200_response_spec.rb +46 -0
  59. data/spec/models/list_conversion_destinations200_response_spec.rb +1 -1
  60. data/spec/models/list_tracking_tags200_response_spec.rb +1 -1
  61. data/spec/models/send_conversions200_response_spec.rb +1 -1
  62. data/spec/models/social_account_spec.rb +1 -1
  63. data/spec/models/update_ad_campaign_status_request_spec.rb +1 -1
  64. data/spec/models/update_ad_set_request_spec.rb +1 -1
  65. metadata +1494 -1482
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
@@ -33862,7 +33921,7 @@ paths:
33862
33921
  put:
33863
33922
  operationId: updateAdSet
33864
33923
  tags: ["Ad Campaigns"]
33865
- x-platforms: ["meta", "tiktok"]
33924
+ x-platforms: ["meta", "tiktok", "openai"]
33866
33925
  summary: Update an ad set
33867
33926
  description: |
33868
33927
  Ad-set-level writes. Use this for ABO budget updates, ad-set-scoped
@@ -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
@@ -33907,21 +33966,25 @@ paths:
33907
33966
  allOf: [{ $ref: '#/components/schemas/BidStrategy' }]
33908
33967
  description: |
33909
33968
  Ad-set-level bid strategy. Overrides the campaign-level default.
33910
- Supported on Meta (facebook, instagram) and TikTok. On TikTok the
33969
+ Supported on Meta (facebook, instagram), TikTok, and OpenAI. On TikTok the
33911
33970
  Meta-style enum is mapped to bid_type / bid_price / deep_bid_type
33912
- automatically. Other platforms (linkedin, pinterest, google, twitter)
33913
- return 501 Not Implemented when bidStrategy is set.
33971
+ automatically. On OpenAI, LOWEST_COST_WITH_BID_CAP and COST_CAP both map to
33972
+ the ad group's `bidding_config.max_bid_micros` (one knob covers both);
33973
+ LOWEST_COST_WITH_MIN_ROAS is rejected with 422 (OpenAI has no ROAS-based
33974
+ bidding). Other platforms (linkedin, pinterest, google, twitter) return 501
33975
+ Not Implemented when bidStrategy is set.
33914
33976
  bidAmount:
33915
33977
  type: number
33916
33978
  description: |
33917
33979
  Bid cap in WHOLE currency units (USD: 5 = $5.00; JPY: 100 = ¥100). Required when
33918
33980
  bidStrategy is LOWEST_COST_WITH_BID_CAP or COST_CAP. Internally converted to Meta's
33919
- smallest-denomination integer.
33981
+ smallest-denomination integer, or (on OpenAI) to micros (× 1,000,000).
33920
33982
  roasAverageFloor:
33921
33983
  type: number
33922
33984
  description: |
33923
33985
  Minimum ROAS as a decimal multiplier (2.0 = 2.0x). Required when bidStrategy is
33924
33986
  LOWEST_COST_WITH_MIN_ROAS. Sent to Meta as `bid_constraints.roas_average_floor` × 10000.
33987
+ Not supported on OpenAI (422).
33925
33988
  platformSpecificData:
33926
33989
  type: object
33927
33990
  description: |
@@ -33968,7 +34031,8 @@ paths:
33968
34031
  '401': { $ref: '#/components/responses/Unauthorized' }
33969
34032
  '404': { description: Ad set not found }
33970
34033
  '409': { description: "Campaign is CBO — route to /v1/ads/campaigns/{campaignId} instead" }
33971
- '501': { description: "bidStrategy not supported on the platform (Meta + TikTok only)" }
34034
+ '422': { description: "bidStrategy is LOWEST_COST_WITH_MIN_ROAS on OpenAI (unsupported: no ROAS-based bidding)" }
34035
+ '501': { description: "bidStrategy not supported on the platform (Meta, TikTok, and OpenAI only)" }
33972
34036
 
33973
34037
  /v1/ads/ad-sets/{adSetId}/status:
33974
34038
  put:
@@ -33994,7 +34058,7 @@ paths:
33994
34058
  required: [status, platform]
33995
34059
  properties:
33996
34060
  status: { type: string, enum: [active, paused] }
33997
- platform: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter] }
34061
+ platform: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter, openai] }
33998
34062
  responses:
33999
34063
  '200':
34000
34064
  description: Ad set status updated
@@ -34033,7 +34097,7 @@ paths:
34033
34097
  - $ref: '#/components/parameters/PageParam'
34034
34098
  - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 100, default: 20 }, description: Campaigns per page }
34035
34099
  - { 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] } }
34100
+ - { name: platform, in: query, schema: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter, openai] } }
34037
34101
  - { name: status, in: query, schema: { $ref: '#/components/schemas/AdStatus' }, description: Filter by derived campaign status (post-aggregation) }
34038
34102
  - { name: adAccountId, in: query, schema: { type: string }, description: Platform ad account ID }
34039
34103
  - { name: accountId, in: query, schema: { type: string }, description: Social account ID }
@@ -34092,7 +34156,7 @@ paths:
34092
34156
  - { 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
34157
  - { name: fromDate, in: query, schema: { type: string, format: date }, description: "Inclusive start of metrics range (YYYY-MM-DD). Defaults to 90 days ago." }
34094
34158
  - { 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. }
34159
+ - { name: platform, in: query, schema: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter, openai] }, description: Restrict to one platform. }
34096
34160
  responses:
34097
34161
  '200':
34098
34162
  description: Daily time series of aggregate metrics. Empty `rows` means the account has no ad activity in the range.
@@ -34185,8 +34249,9 @@ paths:
34185
34249
  - **Meta** (Facebook + Instagram): all fields supported.
34186
34250
  - **TikTok**: status, budget, targeting (via `/v2/adgroup/update/`), and creative
34187
34251
  (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`.
34252
+ - **Pinterest / X / LinkedIn / Google / OpenAI Ads**: status + budget only. Sending
34253
+ `targeting` or `creative` returns 501 with code `unsupported_platform_operation`.
34254
+ OpenAI Ads budget is lifetime-only (see `budget.type` below).
34190
34255
  security:
34191
34256
  - bearerAuth: []
34192
34257
  parameters:
@@ -34203,7 +34268,7 @@ paths:
34203
34268
  type: object
34204
34269
  properties:
34205
34270
  amount: { type: number, description: "Minimum varies by platform: TikTok=$20, Pinterest=$5, others=$1" }
34206
- type: { type: string, enum: [daily, lifetime] }
34271
+ type: { type: string, enum: [daily, lifetime], description: "OpenAI Ads accepts lifetime only; sending daily returns 422." }
34207
34272
  targeting:
34208
34273
  type: object
34209
34274
  description: |
@@ -34261,7 +34326,7 @@ paths:
34261
34326
  tags: ["Ad Campaigns"]
34262
34327
  x-platforms: ["meta", "google", "tiktok", "linkedin", "pinterest", "x"]
34263
34328
  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.
34329
+ 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
34330
  security:
34266
34331
  - bearerAuth: []
34267
34332
  parameters:
@@ -35933,9 +35998,9 @@ paths:
35933
35998
  summary: Create standalone ad
35934
35999
  description: >-
35935
36000
  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
36001
+ Pinterest, TikTok, X/Twitter, LinkedIn, and OpenAI Ads (ChatGPT Ads).
36002
+ Supports three mutually-exclusive request shapes selected by the body,
36003
+ a legacy single-creative shape (all platforms, default), a Meta-only
35939
36004
  multi-creative shape via the creatives array (one ad set with N ads
35940
36005
  sharing budget and targeting), and a Meta-only attach shape via adSetId
35941
36006
  (adds one new ad to an existing ad set). Per-platform required fields,
@@ -36014,6 +36079,9 @@ paths:
36014
36079
  - `engagement`, `traffic`, `awareness` and `video_views` create standalone Direct Sponsored Content ads. `traffic` requires `linkUrl`; `video_views` requires `video`.
36015
36080
  - `job_applicants` requires a `platformSpecificData.jobs` creative.
36016
36081
  - For `lead_generation` or `conversions` on LinkedIn, or to promote an existing post, use POST /v1/ads/boost.
36082
+
36083
+ **OpenAI Ads**
36084
+ - 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
36085
  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
36086
  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
36087
  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 +36093,8 @@ paths:
36025
36093
  validateOnly:
36026
36094
  type: boolean
36027
36095
  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." }
36096
+ 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)." }
36097
+ 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
36098
  status:
36031
36099
  type: string
36032
36100
  enum: [ACTIVE, PAUSED]
@@ -36045,14 +36113,14 @@ paths:
36045
36113
  Meta requires the budget at exactly one level, never both. Non-Meta platforms ignore
36046
36114
  this field. Ignored on the attach shape (`adSetId`), which inherits the existing budget.
36047
36115
  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." }
36116
+ 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
36117
  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." }
36118
+ 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
36119
  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
36120
  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." }
36121
+ 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
36122
  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)." }
36123
+ 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
36124
  images:
36057
36125
  type: object
36058
36126
  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 +36228,7 @@ paths:
36160
36228
  Both forms are equivalent; use whichever your integration already builds.
36161
36229
  allOf:
36162
36230
  - $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.)" }
36231
+ 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
36232
  cities:
36165
36233
  type: array
36166
36234
  description: |
@@ -37810,6 +37878,7 @@ paths:
37810
37878
  - Google Ads (`googleads`) via Data Manager API `ingestEvents`
37811
37879
  - LinkedIn (`linkedinads`) via `/rest/conversionEvents`
37812
37880
  - TikTok (`tiktokads`) via the Offline Events API `/offline/batch/` — OFFLINE conversions only
37881
+ - OpenAI Ads (`openaiads`) via its Conversions API (a separate host, `bzr.openai.com`)
37813
37882
 
37814
37883
  `destinationId` semantics differ per platform:
37815
37884
 
@@ -37817,11 +37886,16 @@ paths:
37817
37886
  - Google: conversion action resource name, e.g. `customers/1234567890/conversionActions/987654321`
37818
37887
  - LinkedIn: conversion rule ID or URN, e.g. `104012` or `urn:lla:llaPartnerConversion:104012`
37819
37888
  - TikTok: Offline Event Set ID, e.g. `7057103914977558530`
37889
+ - OpenAI Ads: pixel wire id (numeric `pixel_id`, distinct from the internal pixel id), as returned by `GET /v1/accounts/{accountId}/conversion-destinations`
37820
37890
 
37821
37891
  TikTok notes: this path sends OFFLINE conversions (in-store / CRM / call-center), not web-pixel
37822
37892
  events. Each event must carry an email or phone (TikTok requires at least one). The connected
37823
37893
  TikTok ads account must have granted the Offline Events permission; older grants must reconnect.
37824
37894
 
37895
+ OpenAI Ads notes: requires a tracking tag (pixel) to already exist on the account — returns 422
37896
+ with code `TRACKING_TAG_REQUIRED` if `POST /v1/accounts/{accountId}/tracking-tags` hasn't been
37897
+ called yet.
37898
+
37825
37899
  Callers can list valid destinations via `GET /v1/accounts/{accountId}/conversion-destinations`.
37826
37900
 
37827
37901
  All PII (email, phone, names, external IDs) is hashed with SHA-256 server-side per each
@@ -37834,7 +37908,9 @@ paths:
37834
37908
 
37835
37909
  Batching is handled automatically. Meta caps at 1000 events per request and rejects the
37836
37910
  entire batch if any event is malformed. Google caps at 2000. LinkedIn caps at 5000 and is
37837
- also all-or-nothing per chunk.
37911
+ also all-or-nothing per chunk. OpenAI Ads caps at 1000 per request; larger submissions are
37912
+ split into 1000-event chunks, each all-or-nothing (a malformed event fails every event in
37913
+ that chunk, not the whole request).
37838
37914
 
37839
37915
  Dedup: pass a stable `eventId` on every event. Meta and LinkedIn use it to dedupe against
37840
37916
  browser-side pixel/Insight Tag events; Google maps it to `transactionId`.
@@ -37844,6 +37920,7 @@ paths:
37844
37920
  - Meta: free-form. Standard names (Purchase, Lead, ...) match Meta's built-in events; custom strings are accepted.
37845
37921
  - 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
37922
  - 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.
37923
+ - 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
37924
  security:
37848
37925
  - bearerAuth: []
37849
37926
  requestBody:
@@ -37856,21 +37933,22 @@ paths:
37856
37933
  properties:
37857
37934
  accountId:
37858
37935
  type: string
37859
- description: SocialAccount ID (metaads, googleads, linkedinads, or tiktokads).
37936
+ description: SocialAccount ID (metaads, googleads, linkedinads, tiktokads, or openaiads).
37860
37937
  destinationId:
37861
37938
  type: string
37862
37939
  description: |
37863
37940
  Platform destination identifier. For Meta, the pixel/dataset
37864
37941
  ID. For Google, the conversion action resource name. For
37865
37942
  LinkedIn, the conversion rule ID or full
37866
- `urn:lla:llaPartnerConversion:{id}` URN.
37943
+ `urn:lla:llaPartnerConversion:{id}` URN. For OpenAI Ads, the
37944
+ pixel wire id.
37867
37945
  events:
37868
37946
  type: array
37869
37947
  minItems: 1
37870
37948
  items: { $ref: '#/components/schemas/ConversionEvent' }
37871
37949
  testCode:
37872
37950
  type: string
37873
- description: Meta `test_event_code` passthrough. Ignored by Google and LinkedIn.
37951
+ description: Meta `test_event_code` passthrough. Ignored by Google, LinkedIn, and OpenAI Ads.
37874
37952
  consent:
37875
37953
  type: object
37876
37954
  description: |
@@ -37891,13 +37969,14 @@ paths:
37891
37969
  partial failure. For Meta, a batch is all-or-nothing (either every
37892
37970
  event in a chunk succeeds, or every event in the chunk is listed
37893
37971
  in failures). For Google, the API returns success/failure at the
37894
- request level only.
37972
+ request level only. For OpenAI Ads, each 1000-event chunk is
37973
+ all-or-nothing, same as Meta.
37895
37974
  content:
37896
37975
  application/json:
37897
37976
  schema:
37898
37977
  type: object
37899
37978
  properties:
37900
- platform: { type: string, enum: [metaads, googleads, linkedinads, tiktokads] }
37979
+ platform: { type: string, enum: [metaads, googleads, linkedinads, tiktokads, openaiads] }
37901
37980
  eventsReceived: { type: integer, description: Events accepted by the platform. }
37902
37981
  eventsFailed: { type: integer, description: Events rejected (see failures). }
37903
37982
  failures:
@@ -37914,7 +37993,8 @@ paths:
37914
37993
  description: |
37915
37994
  Platform trace ID for debugging. fbtrace_id for Meta,
37916
37995
  requestId for Google. Absent for LinkedIn (LinkedIn's
37917
- conversionEvents endpoint does not surface a trace ID).
37996
+ conversionEvents endpoint does not surface a trace ID)
37997
+ and OpenAI Ads (no trace ID surfaced).
37918
37998
  '400':
37919
37999
  description: Invalid body (missing accountId/destinationId/events, malformed event shape).
37920
38000
  '401': { $ref: '#/components/responses/Unauthorized' }
@@ -37924,6 +38004,8 @@ paths:
37924
38004
  OR (for LinkedIn) the connected account lacks the `rw_conversions` scope and must be reconnected.
37925
38005
  '404':
37926
38006
  description: Account not found or not accessible.
38007
+ '422':
38008
+ 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
38009
  '429':
37928
38010
  description: |
37929
38011
  LinkedIn token-level rate limit hit (600 requests/min, 300k/day
@@ -38058,15 +38140,15 @@ paths:
38058
38140
  x-platforms: ["meta", "google", "tiktok", "linkedin"]
38059
38141
  summary: List conversion destinations
38060
38142
  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`.
38143
+ Returns the list of pixels (Meta), conversion actions (Google),
38144
+ conversion rules (LinkedIn), or pixels (OpenAI Ads) accessible to the
38145
+ connected ads account. Use the returned `id` as `destinationId` when
38146
+ posting to `POST /v1/ads/conversions`.
38065
38147
 
38066
38148
  For Google and LinkedIn, each destination's `type` reflects the
38067
38149
  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.
38150
+ locked to the destination. For Meta and OpenAI Ads, `type` is absent:
38151
+ pixels accept any event name per request.
38070
38152
 
38071
38153
  For LinkedIn, destinations are returned across every sponsored ad
38072
38154
  account the connected token can access; the `adAccountId` field on
@@ -38079,7 +38161,7 @@ paths:
38079
38161
  in: path
38080
38162
  required: true
38081
38163
  schema: { type: string }
38082
- description: SocialAccount ID (metaads, googleads, linkedinads, or tiktokads).
38164
+ description: SocialAccount ID (metaads, googleads, linkedinads, tiktokads, or openaiads).
38083
38165
  responses:
38084
38166
  '200':
38085
38167
  description: Destinations listed
@@ -38088,7 +38170,7 @@ paths:
38088
38170
  schema:
38089
38171
  type: object
38090
38172
  properties:
38091
- platform: { type: string, enum: [metaads, googleads, linkedinads, tiktokads] }
38173
+ platform: { type: string, enum: [metaads, googleads, linkedinads, tiktokads, openaiads] }
38092
38174
  destinations:
38093
38175
  type: array
38094
38176
  items:
@@ -38099,7 +38181,8 @@ paths:
38099
38181
  description: |
38100
38182
  Destination identifier. Meta: pixel ID. Google:
38101
38183
  conversion action resource name. LinkedIn:
38102
- numeric conversion rule ID.
38184
+ numeric conversion rule ID. OpenAI Ads: pixel wire
38185
+ id.
38103
38186
  name: { type: string }
38104
38187
  type:
38105
38188
  type: string
@@ -38134,7 +38217,9 @@ paths:
38134
38217
  description: |
38135
38218
  Create a new conversion destination on the platform. Supported for
38136
38219
  LinkedIn (conversion rule) and Google Ads (conversion action). Meta
38137
- manages destinations in its own UI and returns 405.
38220
+ and OpenAI Ads pixels are created via their own tracking-tags flow
38221
+ instead (`POST /v1/accounts/{accountId}/tracking-tags`); this endpoint
38222
+ returns 405 for both.
38138
38223
 
38139
38224
  **LinkedIn:** creation is NOT idempotent. A retry creates a second
38140
38225
  destination. Deduplicate before retrying.
@@ -39041,22 +39126,25 @@ paths:
39041
39126
  x-platforms: ["meta"]
39042
39127
  summary: List tracking tags
39043
39128
  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.
39129
+ Returns the tracking tags (Meta Pixels, or OpenAI Ads pixels) the
39130
+ connected ads account can see. Pass `?adAccountId=act_...` (Meta only)
39131
+ to scope the list to a single ad account; omit it to list every pixel
39132
+ reachable by the token (the name is then suffixed with the ad account
39133
+ it was discovered on, for disambiguation). The list view omits `code`
39134
+ — call `getTrackingTag` for the install snippet and full detail (Meta
39135
+ only; OpenAI Ads has no get-by-id endpoint).
39050
39136
 
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`.
39137
+ Meta (platform `metaads`) and OpenAI Ads (platform `openaiads`); other
39138
+ platforms return 405. The `accountId` must be the ads SocialAccount
39139
+ created by the Ads add-on connect flow (Meta) or the OpenAI Ads
39140
+ connect flow, not a Facebook/Instagram posting account. Get your Meta
39141
+ `act_...` ids from `GET /v1/ads/accounts`; `adAccountId` is ignored for
39142
+ OpenAI Ads (one API key maps to exactly one ad account).
39055
39143
  security:
39056
39144
  - bearerAuth: []
39057
39145
  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`.' }
39146
+ - { name: accountId, in: path, required: true, schema: { type: string }, description: 'Ads SocialAccount id (platform `metaads` or `openaiads`).' }
39147
+ - { 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
39148
  responses:
39061
39149
  '200':
39062
39150
  description: Tracking tags listed
@@ -39065,7 +39153,7 @@ paths:
39065
39153
  schema:
39066
39154
  type: object
39067
39155
  properties:
39068
- platform: { type: string, enum: [metaads] }
39156
+ platform: { type: string, enum: [metaads, openaiads] }
39069
39157
  tags:
39070
39158
  type: array
39071
39159
  items: { $ref: '#/components/schemas/TrackingTag' }
@@ -39081,23 +39169,37 @@ paths:
39081
39169
  x-platforms: ["meta"]
39082
39170
  summary: Create a tracking tag
39083
39171
  description: |
39084
- Creates a Meta Pixel on the given ad account (`POST /act_{id}/adspixels`
39172
+ Meta: creates a Meta Pixel on the given ad account (`POST /act_{id}/adspixels`
39085
39173
  — `name` is the only input). Returns the created tag including its
39086
39174
  install `code`. The pixel is owned by the Business Manager that owns the
39087
39175
  ad account; a pixel created on a personal (non-BM) ad account ends up
39088
39176
  with `ownerBusinessId: null` and can't be shared with other ad accounts.
39089
39177
 
39090
- Creating a pixel does NOT install it — install the returned `code`
39178
+ Creating a Meta pixel does NOT install it — install the returned `code`
39091
39179
  snippet on the site, or send events server-side via
39092
39180
  `POST /v1/ads/conversions`. The check `installed` is derived from
39093
39181
  `lastFiredTime`.
39094
39182
 
39095
- NOT idempotent: each call creates a new pixel. Do not retry blindly on
39096
- timeout. Meta only (platform `metaads`); other platforms return 405.
39183
+ OpenAI Ads: creates an OpenAI pixel AND provisions a Conversions API
39184
+ key for it in the same call (`adAccountId` is required by this
39185
+ endpoint but ignored — one API key maps to exactly one ad account, so
39186
+ there's nothing to select). Returns 422 (`FEATURE_NOT_AVAILABLE`) if
39187
+ the ad account isn't enabled for pixel management; contact your OpenAI
39188
+ partner representative to enable it. There is no delete API for
39189
+ OpenAI pixels. If the pixel is created but the Conversions API key
39190
+ provisioning then fails, the pixel is left live on OpenAI (it cannot
39191
+ be cleaned up) and the error message names the surviving pixel id and
39192
+ warns against retrying, since a retry would create a second, orphaned
39193
+ pixel.
39194
+
39195
+ NOT idempotent on either platform: each call creates a new pixel (and,
39196
+ for OpenAI, a new Conversions API key). Do not retry blindly on
39197
+ timeout. Meta (platform `metaads`) and OpenAI Ads (platform
39198
+ `openaiads`); other platforms return 405.
39097
39199
  security:
39098
39200
  - bearerAuth: []
39099
39201
  parameters:
39100
- - { name: accountId, in: path, required: true, schema: { type: string }, description: 'Meta ads SocialAccount id (platform `metaads`).' }
39202
+ - { name: accountId, in: path, required: true, schema: { type: string }, description: 'Ads SocialAccount id (platform `metaads` or `openaiads`).' }
39101
39203
  requestBody:
39102
39204
  required: true
39103
39205
  content:
@@ -39106,7 +39208,7 @@ paths:
39106
39208
  type: object
39107
39209
  required: [adAccountId, name]
39108
39210
  properties:
39109
- adAccountId: { type: string, description: 'Meta ad account id, e.g. `act_123456789`.' }
39211
+ adAccountId: { type: string, description: 'Meta ad account id, e.g. `act_123456789`. Required by this endpoint but ignored for OpenAI Ads.' }
39110
39212
  name: { type: string, minLength: 1, maxLength: 200 }
39111
39213
  responses:
39112
39214
  '201':
@@ -39116,13 +39218,14 @@ paths:
39116
39218
  schema:
39117
39219
  type: object
39118
39220
  properties:
39119
- platform: { type: string, enum: [metaads] }
39221
+ platform: { type: string, enum: [metaads, openaiads] }
39120
39222
  tag: { $ref: '#/components/schemas/TrackingTag' }
39121
39223
  '400': { description: 'Invalid body, invalid `adAccountId`, over the per-business pixel cap, or ad account not in a Business Manager.' }
39122
39224
  '401': { $ref: '#/components/responses/Unauthorized' }
39123
39225
  '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
39226
  '404': { description: Account not found or not accessible. }
39125
39227
  '405': { description: Platform does not support creating tracking tags. }
39228
+ '422': { description: 'OpenAI Ads only: the ad account is not enabled for pixel management. Contact your OpenAI partner representative.' }
39126
39229
 
39127
39230
  /v1/accounts/{accountId}/tracking-tags/{tagId}:
39128
39231
  get:
@@ -39133,7 +39236,9 @@ paths:
39133
39236
  description: |
39134
39237
  Returns the full tag record including the base-code `code` snippet,
39135
39238
  `lastFiredTime`, `ownerBusinessId`, `isUnavailable`, etc. Meta only
39136
- (platform `metaads`); other platforms return 405.
39239
+ (platform `metaads`); other platforms return 405. OpenAI Ads has no
39240
+ get-by-id endpoint, so it 405s here too — use
39241
+ `GET /v1/accounts/{accountId}/tracking-tags` (list) instead.
39137
39242
  security:
39138
39243
  - bearerAuth: []
39139
39244
  parameters: