late-sdk 0.0.908 → 0.0.910

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 +32 -19
  3. data/docs/AdAccountsApi.md +92 -16
  4. data/docs/AdCampaignsApi.md +20 -20
  5. data/docs/AdCreativesApi.md +222 -0
  6. data/docs/AdInsightsApi.md +16 -16
  7. data/docs/AdTargetingApi.md +4 -4
  8. data/docs/CheckPhoneNumberAvailability200Response.md +1 -1
  9. data/docs/ConversionsApi.md +8 -8
  10. data/docs/GetAdComments200ResponseMeta.md +1 -1
  11. data/docs/ListPartnershipAdContent200Response.md +18 -0
  12. data/docs/ListPartnershipAdContent200ResponseMediaInner.md +30 -0
  13. data/docs/ListPartnershipAdPermissions200Response.md +18 -0
  14. data/docs/ListPartnershipAdPermissions200ResponsePermissionsInner.md +22 -0
  15. data/docs/ListPhoneNumberCountries200ResponseCountriesInnerTypesInner.md +1 -1
  16. data/docs/ListTikTokAdPixels200Response.md +20 -0
  17. data/docs/ListTikTokAdPixels200ResponsePixelsInner.md +26 -0
  18. data/docs/ListTikTokAdPixels200ResponsePixelsInnerEventDetailsInner.md +22 -0
  19. data/docs/ReachAndFrequencyApi.md +16 -16
  20. data/docs/SetPartnershipAdPermission200Response.md +18 -0
  21. data/docs/SetPartnershipAdPermissionRequest.md +22 -0
  22. data/docs/SubmitPhoneNumberKyc200Response.md +1 -1
  23. data/lib/zernio-sdk/api/ad_accounts_api.rb +89 -14
  24. data/lib/zernio-sdk/api/ad_campaigns_api.rb +10 -10
  25. data/lib/zernio-sdk/api/ad_creatives_api.rb +218 -0
  26. data/lib/zernio-sdk/api/ad_insights_api.rb +8 -8
  27. data/lib/zernio-sdk/api/ad_targeting_api.rb +2 -2
  28. data/lib/zernio-sdk/api/conversions_api.rb +4 -4
  29. data/lib/zernio-sdk/api/reach_and_frequency_api.rb +8 -8
  30. data/lib/zernio-sdk/models/check_phone_number_availability200_response.rb +1 -1
  31. data/lib/zernio-sdk/models/get_ad_comments200_response_meta.rb +1 -1
  32. data/lib/zernio-sdk/models/list_partnership_ad_content200_response.rb +149 -0
  33. data/lib/zernio-sdk/models/list_partnership_ad_content200_response_media_inner.rb +205 -0
  34. data/lib/zernio-sdk/models/list_partnership_ad_permissions200_response.rb +149 -0
  35. data/lib/zernio-sdk/models/list_partnership_ad_permissions200_response_permissions_inner.rb +165 -0
  36. data/lib/zernio-sdk/models/list_phone_number_countries200_response_countries_inner_types_inner.rb +1 -1
  37. data/lib/zernio-sdk/models/list_tik_tok_ad_pixels200_response.rb +158 -0
  38. data/lib/zernio-sdk/models/list_tik_tok_ad_pixels200_response_pixels_inner.rb +187 -0
  39. data/lib/zernio-sdk/models/list_tik_tok_ad_pixels200_response_pixels_inner_event_details_inner.rb +166 -0
  40. data/lib/zernio-sdk/models/set_partnership_ad_permission200_response.rb +147 -0
  41. data/lib/zernio-sdk/models/set_partnership_ad_permission_request.rb +219 -0
  42. data/lib/zernio-sdk/models/submit_phone_number_kyc200_response.rb +1 -1
  43. data/lib/zernio-sdk/version.rb +1 -1
  44. data/lib/zernio-sdk.rb +9 -0
  45. data/openapi.yaml +675 -171
  46. data/spec/api/ad_accounts_api_spec.rb +21 -7
  47. data/spec/api/ad_campaigns_api_spec.rb +5 -5
  48. data/spec/api/ad_creatives_api_spec.rb +40 -0
  49. data/spec/api/ad_insights_api_spec.rb +4 -4
  50. data/spec/api/ad_targeting_api_spec.rb +1 -1
  51. data/spec/api/conversions_api_spec.rb +2 -2
  52. data/spec/api/reach_and_frequency_api_spec.rb +4 -4
  53. data/spec/models/list_partnership_ad_content200_response_media_inner_spec.rb +72 -0
  54. data/spec/models/list_partnership_ad_content200_response_spec.rb +36 -0
  55. data/spec/models/list_partnership_ad_permissions200_response_permissions_inner_spec.rb +48 -0
  56. data/spec/models/list_partnership_ad_permissions200_response_spec.rb +36 -0
  57. data/spec/models/list_tik_tok_ad_pixels200_response_pixels_inner_event_details_inner_spec.rb +48 -0
  58. data/spec/models/list_tik_tok_ad_pixels200_response_pixels_inner_spec.rb +60 -0
  59. data/spec/models/list_tik_tok_ad_pixels200_response_spec.rb +42 -0
  60. data/spec/models/set_partnership_ad_permission200_response_spec.rb +36 -0
  61. data/spec/models/set_partnership_ad_permission_request_spec.rb +48 -0
  62. data/zernio-sdk-0.0.910.gem +0 -0
  63. metadata +38 -2
  64. data/zernio-sdk-0.0.908.gem +0 -0
data/openapi.yaml CHANGED
@@ -587,6 +587,26 @@ components:
587
587
  description: Recommended delay before retrying, in seconds.
588
588
  schema: { type: integer, example: 60 }
589
589
  responses:
590
+ AccountUnavailable:
591
+ description: 'The account or requested resource was not found or is not accessible. An account ID may have been disconnected and removed. Read GET /v1/accounts for current account IDs.'
592
+ content:
593
+ application/json:
594
+ schema: { $ref: '#/components/schemas/ErrorResponse' }
595
+ example:
596
+ error: 'Account ID not found. It may have been disconnected and removed. Read GET /v1/accounts for current account IDs.'
597
+ type: not_found
598
+ code: account_not_found
599
+ param: accountId
600
+ AccountConnectionRequired:
601
+ description: 'The account exists but is inactive or needs reconnection. Reconnect it, then read GET /v1/accounts for its current account ID before retrying. Code: ads_connection_required.'
602
+ content:
603
+ application/json:
604
+ schema: { $ref: '#/components/schemas/ErrorResponse' }
605
+ example:
606
+ error: 'This account needs reconnection. Reconnect the account, then read GET /v1/accounts for its current account ID before retrying.'
607
+ type: invalid_request_error
608
+ code: ads_connection_required
609
+ param: accountId
590
610
  IdempotencyKeyInFlight:
591
611
  description: Same Idempotency-Key still processing; retry after a short backoff
592
612
  IdempotencyKeyReused:
@@ -24831,6 +24851,7 @@ paths:
24831
24851
  description: The Instagram account ID
24832
24852
  schema: { type: string }
24833
24853
  responses:
24854
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
24834
24855
  '200':
24835
24856
  description: Active stories
24836
24857
  content:
@@ -24854,8 +24875,7 @@ paths:
24854
24875
  timestamp: { type: [string, "null"], format: date-time, description: When the story was posted. }
24855
24876
  '400': { description: Invalid request. }
24856
24877
  '401': { $ref: '#/components/responses/Unauthorized' }
24857
- '404': { description: Instagram account not found. }
24858
-
24878
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
24859
24879
  /v1/accounts/{accountId}/instagram/publishing-limit:
24860
24880
  get:
24861
24881
  x-resource-group: "accounts"
@@ -24877,6 +24897,7 @@ paths:
24877
24897
  description: The ID of the Instagram account
24878
24898
  schema: { type: string }
24879
24899
  responses:
24900
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
24880
24901
  '200':
24881
24902
  description: Remaining publishing quota for the rolling window
24882
24903
  content:
@@ -24893,7 +24914,8 @@ paths:
24893
24914
  quotaDurationSeconds: 86400
24894
24915
  '400': { description: Not an Instagram account }
24895
24916
  '401': { $ref: '#/components/responses/Unauthorized' }
24896
- '404': { description: Account not found }
24917
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
24918
+
24897
24919
  '502': { description: Instagram rejected the request }
24898
24920
 
24899
24921
  /v1/accounts/{accountId}/instagram/audio:
@@ -24933,6 +24955,7 @@ paths:
24933
24955
  description: 'Search keywords. Omit to get the current trending list.'
24934
24956
  schema: { type: string, minLength: 1, maxLength: 200 }
24935
24957
  responses:
24958
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
24936
24959
  '200':
24937
24960
  description: Matching audio assets (may be empty)
24938
24961
  content:
@@ -24945,7 +24968,8 @@ paths:
24945
24968
  items: { $ref: '#/components/schemas/InstagramAudioAsset' }
24946
24969
  '400': { $ref: '#/components/responses/BadRequest' }
24947
24970
  '401': { $ref: '#/components/responses/Unauthorized' }
24948
- '404': { description: Account not found }
24971
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
24972
+
24949
24973
  '502': { description: Instagram rejected the request }
24950
24974
 
24951
24975
  /v1/accounts/{accountId}/instagram/audio/{audioId}:
@@ -24973,6 +24997,7 @@ paths:
24973
24997
  description: Instagram audio asset ID
24974
24998
  schema: { type: string, pattern: '^\d{1,30}$' }
24975
24999
  responses:
25000
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
24976
25001
  '200':
24977
25002
  description: The audio asset
24978
25003
  content:
@@ -24983,7 +25008,8 @@ paths:
24983
25008
  audio: { $ref: '#/components/schemas/InstagramAudioAsset' }
24984
25009
  '400': { $ref: '#/components/responses/BadRequest' }
24985
25010
  '401': { $ref: '#/components/responses/Unauthorized' }
24986
- '404': { description: Account not found }
25011
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
25012
+
24987
25013
  '502': { description: Instagram rejected the request }
24988
25014
 
24989
25015
  /v1/accounts/{accountId}/instagram/stories/{storyId}/insights:
@@ -25021,6 +25047,7 @@ paths:
25021
25047
  description: The Instagram media ID of the story.
25022
25048
  schema: { type: string }
25023
25049
  responses:
25050
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
25024
25051
  '200':
25025
25052
  description: Story insights
25026
25053
  content:
@@ -25058,7 +25085,8 @@ paths:
25058
25085
  totalInteractions: { type: integer }
25059
25086
  '400': { description: Invalid request. }
25060
25087
  '401': { $ref: '#/components/responses/Unauthorized' }
25061
- '404': { description: Instagram account not found. }
25088
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
25089
+
25062
25090
  '502': { description: 'Instagram rejected the request.' }
25063
25091
 
25064
25092
  /v1/accounts/{accountId}/pinterest-boards:
@@ -36337,7 +36365,7 @@ paths:
36337
36365
  callsAvailable: { type: boolean }
36338
36366
  inStock: { type: boolean }
36339
36367
  fulfilment: { type: string, enum: [instant, request], description: "`request`: the carrier stocks this type nowhere and only sources it to order, so it is always a pre-order." }
36340
- preOrderable: { type: boolean, description: "Out of stock but orderable anyway. Submit KYC as usual (POST /v1/phone-numbers/kyc) and the carrier sources the number after review, usually about 3 weeks and never guaranteed. Only document tiers (3/4) qualify, and nothing is billed until the number is active." }
36368
+ preOrderable: { type: boolean, description: "Out of stock but orderable anyway. Submit KYC as usual (POST /v1/phone-numbers/kyc): we buy regular stock the moment it returns, otherwise the carrier sources the number. Usually 2 to 4 weeks, never guaranteed. Only document tiers (3/4) qualify, and nothing is billed until the number is active." }
36341
36369
  '401': { $ref: '#/components/responses/Unauthorized' }
36342
36370
 
36343
36371
  /v1/phone-numbers/available:
@@ -36416,7 +36444,7 @@ paths:
36416
36444
  country: { type: string }
36417
36445
  numberType: { type: string }
36418
36446
  available: { type: boolean, description: Whether deliverable voice inventory exists right now. }
36419
- preOrderable: { type: boolean, description: "Nothing deliverable now, but this pair can be pre-ordered: submit KYC as usual and the carrier sources the number after review (usually about 3 weeks, never guaranteed). Only document tiers (3/4) qualify." }
36447
+ preOrderable: { type: boolean, description: "Nothing deliverable now, but this pair can be pre-ordered: submit KYC as usual and we buy regular stock the moment it returns, otherwise the carrier sources the number (usually 2 to 4 weeks, never guaranteed). Only document tiers (3/4) qualify." }
36420
36448
  addressConstraint: { type: string, enum: [geo, country, none] }
36421
36449
  areas:
36422
36450
  type: array
@@ -36802,7 +36830,7 @@ paths:
36802
36830
  country: { type: string }
36803
36831
  numberType: { type: string }
36804
36832
  available: { type: boolean, description: Whether deliverable voice inventory exists right now. }
36805
- preOrderable: { type: boolean, description: "Nothing deliverable now, but this pair can be pre-ordered: submit KYC as usual and the carrier sources the number after review (usually about 3 weeks, never guaranteed). Only document tiers (3/4) qualify." }
36833
+ preOrderable: { type: boolean, description: "Nothing deliverable now, but this pair can be pre-ordered: submit KYC as usual and we buy regular stock the moment it returns, otherwise the carrier sources the number (usually 2 to 4 weeks, never guaranteed). Only document tiers (3/4) qualify." }
36806
36834
  addressConstraint: { type: string, enum: [geo, country, none] }
36807
36835
  areas:
36808
36836
  type: array
@@ -36987,7 +37015,7 @@ paths:
36987
37015
  type: object
36988
37016
  properties:
36989
37017
  status: { type: string, enum: [kyc_submitted, kyc_reused, kyc_already_submitted] }
36990
- preOrder: { type: boolean, description: "True when nothing was in stock and this submission placed a pre-order. The number stays `pending_regulatory` until the carrier sources it (usually about 3 weeks) and is not billed until active. A pre-order is one number: `quantity` above 1 is rejected with 400." }
37018
+ preOrder: { type: boolean, description: "True when nothing was in stock and this submission placed a pre-order. The number stays `pending_regulatory` until we get it, from regular stock the moment it returns or sourced by the carrier (usually 2 to 4 weeks), and is not billed until active. Releasing it (DELETE /v1/phone-numbers/{id}) cancels the pre-order. A pre-order is one number: `quantity` above 1 is rejected with 400." }
36991
37019
  phoneNumber:
36992
37020
  type: object
36993
37021
  description: The first/primary number, kept at the top level for backward compatibility. See `numbers` for the full set when `quantity` > 1.
@@ -37981,7 +38009,7 @@ paths:
37981
38009
  type: object
37982
38010
  properties:
37983
38011
  status: { type: string, enum: [kyc_submitted, kyc_reused, kyc_already_submitted] }
37984
- preOrder: { type: boolean, description: "True when nothing was in stock and this submission placed a pre-order. The number stays `pending_regulatory` until the carrier sources it (usually about 3 weeks) and is not billed until active. A pre-order is one number: `quantity` above 1 is rejected with 400." }
38012
+ preOrder: { type: boolean, description: "True when nothing was in stock and this submission placed a pre-order. The number stays `pending_regulatory` until we get it, from regular stock the moment it returns or sourced by the carrier (usually 2 to 4 weeks), and is not billed until active. Releasing it (DELETE /v1/phone-numbers/{id}) cancels the pre-order. A pre-order is one number: `quantity` above 1 is rejected with 400." }
37985
38013
  phoneNumber:
37986
38014
  type: object
37987
38015
  description: The first/primary number, kept at the top level for backward compatibility. See `numbers` for the full set when `quantity` > 1.
@@ -42847,6 +42875,8 @@ paths:
42847
42875
  - { name: adGroupId, in: query, schema: { type: string }, description: "Numeric Google ad group id filter." }
42848
42876
  - { name: pageToken, in: query, schema: { type: string }, description: "Cursor from paging.nextPageToken of the previous page." }
42849
42877
  responses:
42878
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
42879
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
42850
42880
  '200':
42851
42881
  description: Search terms
42852
42882
  content:
@@ -42889,7 +42919,7 @@ paths:
42889
42919
  operationId: listBidStrategies
42890
42920
  tags: ["Ad Campaigns"]
42891
42921
  x-platforms: ["google"]
42892
- summary: List Google Ads portfolio bid strategies
42922
+ summary: 'List portfolio bid strategies'
42893
42923
  description: >-
42894
42924
  Bidding strategy report: type, status, campaign count, clicks, cost, cost per
42895
42925
  conversion, impressions, average CPC and conversions over the date range (default
@@ -42905,6 +42935,7 @@ paths:
42905
42935
  - { name: fromDate, in: query, schema: { type: string, format: date }, description: "Defaults to 30 days ago." }
42906
42936
  - { name: toDate, in: query, schema: { type: string, format: date }, description: "Defaults to today." }
42907
42937
  responses:
42938
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
42908
42939
  '200':
42909
42940
  description: Portfolio bid strategies
42910
42941
  content:
@@ -42921,7 +42952,8 @@ paths:
42921
42952
  stale: { type: boolean, description: "True when Google's daily API quota was exhausted and this is the last successful fetch, not a live read." }
42922
42953
  '400': { $ref: '#/components/responses/BadRequest' }
42923
42954
  '401': { $ref: '#/components/responses/Unauthorized' }
42924
- '404': { $ref: '#/components/responses/NotFound' }
42955
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
42956
+
42925
42957
  '429': { description: "Google Ads operations budget exhausted; retry later." }
42926
42958
  '501': { description: Only available on Google Ads accounts }
42927
42959
  post:
@@ -42929,7 +42961,7 @@ paths:
42929
42961
  operationId: createBidStrategy
42930
42962
  tags: ["Ad Campaigns"]
42931
42963
  x-platforms: ["google"]
42932
- summary: Create a Google Ads portfolio bid strategy
42964
+ summary: 'Create portfolio bid strategy'
42933
42965
  description: >-
42934
42966
  Creates a standalone bid strategy shared across campaigns. Attach it to a campaign
42935
42967
  with `portfolioBidStrategyId` on POST /v1/ads/create, PUT /v1/ads/campaigns/{campaignId},
@@ -42952,6 +42984,7 @@ paths:
42952
42984
  targetCpa: { type: number, exclusiveMinimum: 0, description: "Required when type is TARGET_CPA, in the account's currency units." }
42953
42985
  targetRoas: { type: number, exclusiveMinimum: 0, description: "Required when type is TARGET_ROAS; a multiplier (2.0 = 2.0x)." }
42954
42986
  responses:
42987
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
42955
42988
  '201':
42956
42989
  description: Bid strategy created
42957
42990
  content:
@@ -42967,7 +43000,8 @@ paths:
42967
43000
  resourceName: { type: string }
42968
43001
  '400': { description: "Invalid input, or Google rejected the strategy (e.g. shared-budget alignment). The message carries Google's error." }
42969
43002
  '401': { $ref: '#/components/responses/Unauthorized' }
42970
- '404': { $ref: '#/components/responses/NotFound' }
43003
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
43004
+
42971
43005
  '422': { description: "No Google Ads customer accounts on this connection. Reconnect Google Ads." }
42972
43006
  '429': { description: "Google Ads operations budget exhausted; retry later." }
42973
43007
  '501': { description: Only available on Google Ads accounts }
@@ -42978,7 +43012,7 @@ paths:
42978
43012
  operationId: updateBidStrategy
42979
43013
  tags: ["Ad Campaigns"]
42980
43014
  x-platforms: ["google"]
42981
- summary: Update a Google Ads portfolio bid strategy
43015
+ summary: 'Update portfolio bid strategy'
42982
43016
  description: >-
42983
43017
  Renames or retargets a portfolio bid strategy. The strategy's status is output only
42984
43018
  on Google's side, so it cannot be changed here; remove a strategy in Google Ads.
@@ -43005,6 +43039,7 @@ paths:
43005
43039
  targetCpa: { type: number, exclusiveMinimum: 0 }
43006
43040
  targetRoas: { type: number, exclusiveMinimum: 0 }
43007
43041
  responses:
43042
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
43008
43043
  '200':
43009
43044
  description: Bid strategy updated
43010
43045
  content:
@@ -43018,7 +43053,8 @@ paths:
43018
43053
  customerId: { type: string }
43019
43054
  '400': { $ref: '#/components/responses/BadRequest' }
43020
43055
  '401': { $ref: '#/components/responses/Unauthorized' }
43021
- '404': { $ref: '#/components/responses/NotFound' }
43056
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
43057
+
43022
43058
  '429': { description: "Google Ads operations budget exhausted; retry later." }
43023
43059
  '501': { description: Only available on Google Ads accounts }
43024
43060
 
@@ -43048,6 +43084,8 @@ paths:
43048
43084
  - { name: chargedOnly, in: query, schema: { type: boolean }, description: "true = only leads Google charged for." }
43049
43085
  - { name: pageToken, in: query, schema: { type: string }, description: "Cursor from paging.nextPageToken of the previous page." }
43050
43086
  responses:
43087
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
43088
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
43051
43089
  '200':
43052
43090
  description: Local Services leads
43053
43091
  content:
@@ -43093,7 +43131,7 @@ paths:
43093
43131
  operationId: listLocalServicesLeadConversations
43094
43132
  tags: ["Ad Insights"]
43095
43133
  x-platforms: ["google"]
43096
- summary: Conversations of a Local Services lead
43134
+ summary: 'List lead conversations'
43097
43135
  description: |-
43098
43136
  Conversation entries of one Local Services lead: phone calls (duration,
43099
43137
  recording URL) and messages (text, attachment URLs), oldest first. Read
@@ -43108,6 +43146,8 @@ paths:
43108
43146
  - { name: customerId, in: query, schema: { type: string }, description: "Numeric Google Ads customer id (no dashes). Defaults to the account's connected customer." }
43109
43147
  - { name: pageToken, in: query, schema: { type: string }, description: "Cursor from paging.nextPageToken of the previous page." }
43110
43148
  responses:
43149
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
43150
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
43111
43151
  '200':
43112
43152
  description: Lead conversations
43113
43153
  content:
@@ -43199,7 +43239,7 @@ paths:
43199
43239
  operationId: addAdKeywords
43200
43240
  tags: ["Ad Campaigns"]
43201
43241
  x-platforms: ["google"]
43202
- summary: Add Search keywords to an ad group
43242
+ summary: 'Add Search ad-group keywords'
43203
43243
  description: |
43204
43244
  Adds one or more keyword criteria to an existing Google Search ad group,
43205
43245
  without touching the keywords already there (unlike the whole-set diff on
@@ -43233,6 +43273,7 @@ paths:
43233
43273
  matchType: { type: string, enum: [exact, phrase, broad] }
43234
43274
  negative: { type: boolean, default: false, description: 'Add as ad-group-level negatives instead of positive keywords' }
43235
43275
  responses:
43276
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
43236
43277
  '201':
43237
43278
  description: Keywords added
43238
43279
  content:
@@ -43245,7 +43286,8 @@ paths:
43245
43286
  items: { $ref: '#/components/schemas/AdKeyword' }
43246
43287
  '400': { $ref: '#/components/responses/BadRequest' }
43247
43288
  '401': { $ref: '#/components/responses/Unauthorized' }
43248
- '404': { description: 'The ad group ("adSetId") was not found for this account.' }
43289
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
43290
+
43249
43291
  '501': { description: Only available on Google Ads accounts }
43250
43292
 
43251
43293
  /v1/ads/keywords/{keywordId}:
@@ -43272,6 +43314,7 @@ paths:
43272
43314
  properties:
43273
43315
  status: { type: string, enum: [active, paused] }
43274
43316
  responses:
43317
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
43275
43318
  '200':
43276
43319
  description: Keyword updated
43277
43320
  content:
@@ -43282,7 +43325,8 @@ paths:
43282
43325
  keyword: { $ref: '#/components/schemas/AdKeyword' }
43283
43326
  '400': { $ref: '#/components/responses/BadRequest' }
43284
43327
  '401': { $ref: '#/components/responses/Unauthorized' }
43285
- '404': { description: Keyword not found }
43328
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
43329
+
43286
43330
  '422': { description: 'Negative keywords have no status on Google; they cannot be paused or enabled.' }
43287
43331
  delete:
43288
43332
  x-resource-group: "ads"
@@ -43296,6 +43340,7 @@ paths:
43296
43340
  parameters:
43297
43341
  - { name: keywordId, in: path, required: true, schema: { type: string }, description: Zernio keyword ID (not the Google criterion ID) }
43298
43342
  responses:
43343
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
43299
43344
  '200':
43300
43345
  description: Keyword removed
43301
43346
  content:
@@ -43307,8 +43352,7 @@ paths:
43307
43352
  keywordId: { type: string }
43308
43353
  '400': { $ref: '#/components/responses/BadRequest' }
43309
43354
  '401': { $ref: '#/components/responses/Unauthorized' }
43310
- '404': { description: Keyword not found }
43311
-
43355
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
43312
43356
  /v1/ads/campaigns:
43313
43357
  get:
43314
43358
  x-resource-group: "ads"
@@ -43351,6 +43395,8 @@ paths:
43351
43395
  - { name: hasDelivery, in: query, schema: { type: boolean }, description: "Return only campaigns that delivered between `fromDate` and `toDate`: spend above zero, or impressions served at zero spend. Unlike `status`, which reads a campaign's CURRENT state, this filters on what happened inside the window. Filters the campaign set itself, so `pagination.total` counts only matching campaigns. Mirrors the same filter on /v1/ads/tree." }
43352
43396
  - { name: minSpend, in: query, schema: { type: number, minimum: 0 }, description: "Return only campaigns whose spend between `fromDate` and `toDate` reaches this amount, in each campaign's OWN currency (the `currency` field on the campaign). Implies `hasDelivery`; `minSpend=0` applies no filter. Mirrors the same filter on /v1/ads/tree." }
43353
43397
  responses:
43398
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
43399
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
43354
43400
  '200':
43355
43401
  description: Paginated campaigns
43356
43402
  content:
@@ -43465,6 +43511,8 @@ paths:
43465
43511
  status: PAUSED
43466
43512
  validateOnly: true
43467
43513
  responses:
43514
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
43515
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
43468
43516
  '200':
43469
43517
  description: 'Campaign validation passed without creating a campaign.'
43470
43518
  content:
@@ -43578,6 +43626,7 @@ paths:
43578
43626
  - { name: platform, in: query, required: true, schema: { type: string, enum: [google] }, description: "Required: campaign IDs are not globally unique. Only \"google\" is supported today." }
43579
43627
  - { name: customerId, in: query, required: false, schema: { type: string }, description: "Numeric Google Ads customer id (no dashes). Required when the connection has multiple Google Ads accounts; optional (and inferred) when it has only one." }
43580
43628
  responses:
43629
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
43581
43630
  '200':
43582
43631
  description: Campaign bidding
43583
43632
  content:
@@ -43593,8 +43642,8 @@ paths:
43593
43642
  '401': { $ref: '#/components/responses/Unauthorized' }
43594
43643
  '403':
43595
43644
  description: "Ads access required. Legacy plans need the Ads add-on; included by default on usage-based plans."
43596
- '404':
43597
- description: Campaign not found on Google Ads
43645
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
43646
+
43598
43647
  '501':
43599
43648
  description: "Not a Google Ads account: the connection behind accountId resolves to another platform."
43600
43649
 
@@ -43693,8 +43742,9 @@ paths:
43693
43742
  '401': { $ref: '#/components/responses/Unauthorized' }
43694
43743
  '403':
43695
43744
  description: 'Returned with code `ads_allowance_exceeded` when the team has no payment method on file and has reached the 500 free live ads: add a card to resume.'
43696
- '404': { description: Campaign not found }
43697
- '409': { description: "Meta campaign is ABO, or the Google budget is shared without allowSharedBudgetUpdate=true, or sharing state cannot be verified." }
43745
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
43746
+
43747
+ '409': { description: 'Meta campaign is ABO, or the Google budget is shared without allowSharedBudgetUpdate=true, or sharing state cannot be verified. The account may also be inactive or need reconnection (code ads_connection_required). Reconnect it and read GET /v1/accounts for its current ID before retrying.' }
43698
43748
  '501': { description: Operation not supported on this platform }
43699
43749
 
43700
43750
  delete:
@@ -43730,6 +43780,8 @@ paths:
43730
43780
  platform: { type: string, enum: [facebook, instagram, google] }
43731
43781
  accountId: { type: string, description: "Zernio SocialAccount id owning the ad account. Required only to delete an EMPTY campaign (zero ads), which has no local Ad documents to resolve a token from." }
43732
43782
  responses:
43783
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
43784
+ '400': { $ref: '#/components/responses/BadRequest' }
43733
43785
  '200':
43734
43786
  description: Campaign deleted
43735
43787
  content:
@@ -43740,7 +43792,8 @@ paths:
43740
43792
  deleted: { type: boolean }
43741
43793
  adCount: { type: integer, description: Number of local Ad docs marked cancelled }
43742
43794
  '401': { $ref: '#/components/responses/Unauthorized' }
43743
- '404': { description: Campaign not found }
43795
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
43796
+
43744
43797
  '501': { description: Operation not supported on this platform }
43745
43798
 
43746
43799
  /v1/ads/campaigns/{campaignId}/negative-keywords:
@@ -44285,6 +44338,7 @@ paths:
44285
44338
  status: { type: string, enum: [ACTIVE, PAUSED], default: PAUSED }
44286
44339
  customerId: { type: string, description: "Numeric Google Ads customer id. Only required when the connection has more than one." }
44287
44340
  responses:
44341
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
44288
44342
  '201':
44289
44343
  description: Ad group created
44290
44344
  content:
@@ -44298,7 +44352,8 @@ paths:
44298
44352
  '401': { $ref: '#/components/responses/Unauthorized' }
44299
44353
  '403':
44300
44354
  description: 'Returned with code `ads_allowance_exceeded` when the team has no payment method on file and has reached the 500 free live ads: add a card to resume.'
44301
- '404': { description: accountId does not belong to a Google Ads connection }
44355
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
44356
+
44302
44357
  '501': { description: Only supported on Google Ads }
44303
44358
 
44304
44359
  /v1/ads/ad-sets/{adSetId}/duplicate:
@@ -44429,7 +44484,7 @@ paths:
44429
44484
  operationId: getAdSetDetails
44430
44485
  tags: ["Ad Campaigns"]
44431
44486
  x-platforms: ["meta"]
44432
- summary: Live ad-set details incl. learning phase
44487
+ summary: 'Get live ad-set details'
44433
44488
  description: |-
44434
44489
  Reads the ad set live from Meta, returned verbatim. The default projection includes
44435
44490
  `learning_stage_info` (learning-phase status: LEARNING / SUCCESS / FAIL / WAIVING; Meta
@@ -44443,6 +44498,8 @@ paths:
44443
44498
  - { name: accountId, in: query, required: true, schema: { type: string }, description: "Zernio SocialAccount id (posting or ads variant) used to resolve the Meta token." }
44444
44499
  - { name: fields, in: query, schema: { type: string }, description: "Comma-separated Graph field override (supports nested {} projections)." }
44445
44500
  responses:
44501
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
44502
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
44446
44503
  '200':
44447
44504
  description: The ad set as returned by Meta
44448
44505
  content:
@@ -45263,6 +45320,7 @@ paths:
45263
45320
  pattern: ^\d+$
45264
45321
  description: "Google customer id without dashes. Required when the connection has multiple customers."
45265
45322
  responses:
45323
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
45266
45324
  '200':
45267
45325
  description: "Assets returned."
45268
45326
  content:
@@ -45331,8 +45389,8 @@ paths:
45331
45389
  $ref: '#/components/responses/Unauthorized'
45332
45390
  '403':
45333
45391
  description: "Ads access is required."
45334
- '404':
45335
- $ref: '#/components/responses/NotFound'
45392
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
45393
+
45336
45394
  '429':
45337
45395
  description: "Google Ads operations budget or platform quota exhausted."
45338
45396
  '501':
@@ -45412,6 +45470,7 @@ paths:
45412
45470
  - Analytics
45413
45471
  - Messaging
45414
45472
  responses:
45473
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
45415
45474
  '201':
45416
45475
  description: "Assets created and attached."
45417
45476
  content:
@@ -45439,8 +45498,8 @@ paths:
45439
45498
  $ref: '#/components/responses/Unauthorized'
45440
45499
  '403':
45441
45500
  description: "Ads access is required."
45442
- '404':
45443
- $ref: '#/components/responses/NotFound'
45501
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
45502
+
45444
45503
  '429':
45445
45504
  description: "Google Ads operations budget or platform quota exhausted."
45446
45505
  '501':
@@ -45498,6 +45557,7 @@ paths:
45498
45557
  calloutAsset:
45499
45558
  calloutText: Simple integration
45500
45559
  responses:
45560
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
45501
45561
  '200':
45502
45562
  description: "Assets returned."
45503
45563
  content:
@@ -45513,8 +45573,8 @@ paths:
45513
45573
  $ref: '#/components/responses/Unauthorized'
45514
45574
  '403':
45515
45575
  description: "Ads access is required."
45516
- '404':
45517
- $ref: '#/components/responses/NotFound'
45576
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
45577
+
45518
45578
  '429':
45519
45579
  description: "Google Ads operations budget or platform quota exhausted."
45520
45580
  '501':
@@ -45575,6 +45635,7 @@ paths:
45575
45635
  campaignAssetResourceNames:
45576
45636
  - customers/1234567890/campaignAssets/456~123~CALLOUT
45577
45637
  responses:
45638
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
45578
45639
  '200':
45579
45640
  description: "Assets returned."
45580
45641
  content:
@@ -45590,8 +45651,8 @@ paths:
45590
45651
  $ref: '#/components/responses/Unauthorized'
45591
45652
  '403':
45592
45653
  description: "Ads access is required."
45593
- '404':
45594
- $ref: '#/components/responses/NotFound'
45654
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
45655
+
45595
45656
  '429':
45596
45657
  description: "Google Ads operations budget or platform quota exhausted."
45597
45658
  '501':
@@ -45632,6 +45693,7 @@ paths:
45632
45693
  pattern: ^\d+$
45633
45694
  description: "Google customer id without dashes. Required when the connection has multiple customers."
45634
45695
  responses:
45696
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
45635
45697
  '200':
45636
45698
  description: "Assets returned."
45637
45699
  content:
@@ -45700,8 +45762,8 @@ paths:
45700
45762
  $ref: '#/components/responses/Unauthorized'
45701
45763
  '403':
45702
45764
  description: "Ads access is required."
45703
- '404':
45704
- $ref: '#/components/responses/NotFound'
45765
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
45766
+
45705
45767
  '429':
45706
45768
  description: "Google Ads operations budget or platform quota exhausted."
45707
45769
  '501':
@@ -45781,6 +45843,7 @@ paths:
45781
45843
  - Analytics
45782
45844
  - Messaging
45783
45845
  responses:
45846
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
45784
45847
  '201':
45785
45848
  description: "Assets created and attached."
45786
45849
  content:
@@ -45808,8 +45871,8 @@ paths:
45808
45871
  $ref: '#/components/responses/Unauthorized'
45809
45872
  '403':
45810
45873
  description: "Ads access is required."
45811
- '404':
45812
- $ref: '#/components/responses/NotFound'
45874
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
45875
+
45813
45876
  '429':
45814
45877
  description: "Google Ads operations budget or platform quota exhausted."
45815
45878
  '501':
@@ -45867,6 +45930,7 @@ paths:
45867
45930
  calloutAsset:
45868
45931
  calloutText: Simple integration
45869
45932
  responses:
45933
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
45870
45934
  '200':
45871
45935
  description: "Assets returned."
45872
45936
  content:
@@ -45882,8 +45946,8 @@ paths:
45882
45946
  $ref: '#/components/responses/Unauthorized'
45883
45947
  '403':
45884
45948
  description: "Ads access is required."
45885
- '404':
45886
- $ref: '#/components/responses/NotFound'
45949
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
45950
+
45887
45951
  '429':
45888
45952
  description: "Google Ads operations budget or platform quota exhausted."
45889
45953
  '501':
@@ -45944,6 +46008,7 @@ paths:
45944
46008
  adGroupAssetResourceNames:
45945
46009
  - customers/1234567890/adGroupAssets/456~123~CALLOUT
45946
46010
  responses:
46011
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
45947
46012
  '200':
45948
46013
  description: "Assets returned."
45949
46014
  content:
@@ -45959,8 +46024,8 @@ paths:
45959
46024
  $ref: '#/components/responses/Unauthorized'
45960
46025
  '403':
45961
46026
  description: "Ads access is required."
45962
- '404':
45963
- $ref: '#/components/responses/NotFound'
46027
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
46028
+
45964
46029
  '429':
45965
46030
  description: "Google Ads operations budget or platform quota exhausted."
45966
46031
  '501':
@@ -46084,6 +46149,8 @@ paths:
46084
46149
  additionalProperties: true
46085
46150
  description: "Raw Meta creative spec forwarded verbatim to /generatepreviews. Mutually exclusive with existingCreativeId."
46086
46151
  responses:
46152
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
46153
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
46087
46154
  '200':
46088
46155
  description: Rendered previews
46089
46156
  content:
@@ -46195,7 +46262,7 @@ paths:
46195
46262
  operationId: generateKeywordIdeas
46196
46263
  tags: ["Ad Insights"]
46197
46264
  x-platforms: ["google"]
46198
- summary: Generate keyword ideas (Google Keyword Planner)
46265
+ summary: 'Generate keyword ideas'
46199
46266
  description: |
46200
46267
  Google Ads only. Runs Keyword Planner's generateKeywordIdeas from seed keywords, a seed URL,
46201
46268
  or both, returning idea rows verbatim (avgMonthlySearches, competition, competitionIndex,
@@ -46222,6 +46289,8 @@ paths:
46222
46289
  pageSize: { type: integer, minimum: 1, maximum: 10000 }
46223
46290
  pageToken: { type: string, description: "Cursor from paging.nextPageToken of the previous page." }
46224
46291
  responses:
46292
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
46293
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
46225
46294
  '200':
46226
46295
  description: Keyword idea rows (raw Keyword Planner shape)
46227
46296
  content:
@@ -46249,7 +46318,7 @@ paths:
46249
46318
  operationId: generateKeywordHistoricalMetrics
46250
46319
  tags: ["Ad Insights"]
46251
46320
  x-platforms: ["google"]
46252
- summary: Historical keyword metrics (Google Keyword Planner)
46321
+ summary: 'Get historical keyword metrics'
46253
46322
  description: |
46254
46323
  Google Ads only. Runs Keyword Planner's generateKeywordHistoricalMetrics for up to 1,000
46255
46324
  exact keywords: historical search volume, competition and top-of-page bid ranges, plus
@@ -46274,6 +46343,8 @@ paths:
46274
46343
  includeAdultKeywords: { type: boolean }
46275
46344
  includeAverageCpc: { type: boolean, description: "Adds averageCpcMicros to each row's keywordMetrics." }
46276
46345
  responses:
46346
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
46347
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
46277
46348
  '200':
46278
46349
  description: Historical metric rows (raw Keyword Planner shape)
46279
46350
  content:
@@ -46337,6 +46408,8 @@ paths:
46337
46408
  - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 500, default: 25 }, description: Rows per page }
46338
46409
  - { name: after, in: query, schema: { type: string }, description: "Cursor from paging.after of the previous page." }
46339
46410
  responses:
46411
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
46412
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
46340
46413
  '200':
46341
46414
  description: Insight rows (raw platform shape)
46342
46415
  content:
@@ -46366,7 +46439,7 @@ paths:
46366
46439
  operationId: createAdInsightsReport
46367
46440
  tags: ["Ad Insights"]
46368
46441
  x-platforms: ["meta"]
46369
- summary: Submit an async insights report run
46442
+ summary: 'Submit async insights report'
46370
46443
  description: |
46371
46444
  Submits an asynchronous Meta insights report. Same query surface as GET /v1/ads/insights, but
46372
46445
  in the JSON body; Meta processes the report server-side, which is the right choice for long
@@ -46410,6 +46483,8 @@ paths:
46410
46483
  timeIncrement:
46411
46484
  oneOf: [{ type: integer, minimum: 1, maximum: 90 }, { type: string, enum: [monthly, all_days] }]
46412
46485
  responses:
46486
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
46487
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
46413
46488
  '202':
46414
46489
  description: Report run submitted
46415
46490
  content:
@@ -46443,6 +46518,8 @@ paths:
46443
46518
  - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 500, default: 25 } }
46444
46519
  - { name: after, in: query, schema: { type: string } }
46445
46520
  responses:
46521
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
46522
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
46446
46523
  '200':
46447
46524
  description: Report run status (plus results when completed)
46448
46525
  content:
@@ -46675,12 +46752,22 @@ paths:
46675
46752
  each page to this ad. A page can be empty while `pagination.hasMore` is true.
46676
46753
  Reuse `pagination.cursor` with the same `limit`; the cursor retains the date window.
46677
46754
  `placement` is Meta-only and returns a 400 for TikTok.
46755
+ Listing needs no identity or video item ID. When the ad group is stored, each
46756
+ page makes one comment-list call and no ad-detail lookup, including for external
46757
+ ads that TikTok no longer returns from ad details. `meta.tiktokItemId: null`
46758
+ does not prevent listing. If the ad group is missing, Zernio fetches ad details;
46759
+ unavailable details return 404 ad_not_found, and no ad group returns 400 ad_not_commentable.
46678
46760
 
46679
46761
  TikTok returns replies as separate comments with `parentId`; nested reply fetching
46680
- is not supported. `canReply` requires a first-level comment and an identity with
46681
- comment-management permission. `canDelete` reflects TikTok's own-comment deletion
46682
- capability. `canHide` is supported and `canLike` is false. Use the ad comment
46683
- reply, hide and delete operations below to moderate TikTok comments.
46762
+ is not supported. `canReply` requires a first-level comment, comment-management
46763
+ permission, a video item ID and a supported TT_USER or CUSTOMIZED_USER identity.
46764
+ `canDelete` requires TikTok's own-comment deletion capability, a video item ID
46765
+ and a supported identity. Both flags are false when identity or item is unknown.
46766
+ Listing uses stored and comment-specific fields without fetching identity.
46767
+ A direct reply or delete request can lazily resolve missing fields and succeed
46768
+ even after a false flag. `canHide` is true because visibility changes need only
46769
+ advertiser and comment IDs. `canLike` is false. Use the ad comment reply, hide
46770
+ and delete operations below to moderate TikTok comments.
46684
46771
  Other platforms return feature_not_available.
46685
46772
 
46686
46773
  Requires the Ads add-on. Response shape matches GET /v1/inbox/comments/{postId}.
@@ -46732,7 +46819,7 @@ paths:
46732
46819
  description: "Underlying post ID the comments belong to. effective_object_story_id for the Facebook side, effective_instagram_media_id for the Instagram side."
46733
46820
  tiktokItemId:
46734
46821
  type: [string, "null"]
46735
- description: "TikTok-only video item ID. Null when the ad and comments do not expose it."
46822
+ description: "TikTok-only video item ID from stored ad fields or returned comments. Null does not prevent listing; ad details are not fetched to populate it."
46736
46823
  since: { type: string, format: date, description: "TikTok-only resolved start date." }
46737
46824
  until: { type: string, format: date, description: "TikTok-only resolved end date." }
46738
46825
  facebookAccountId:
@@ -46762,7 +46849,7 @@ paths:
46762
46849
  url: null
46763
46850
  replies: []
46764
46851
  isHidden: false
46765
- canReply: true
46852
+ canReply: false
46766
46853
  canDelete: false
46767
46854
  canHide: true
46768
46855
  canLike: false
@@ -46773,7 +46860,7 @@ paths:
46773
46860
  adId: "507f1f77bcf86cd799439011"
46774
46861
  platformAdId: "1790166588666881"
46775
46862
  accountId: "507f1f77bcf86cd799439012"
46776
- tiktokItemId: "7512345678901234500"
46863
+ tiktokItemId: null
46777
46864
  since: "2026-08-10"
46778
46865
  until: "2026-09-09"
46779
46866
  lastUpdated: "2026-09-09T12:00:00.000Z"
@@ -46800,6 +46887,14 @@ paths:
46800
46887
  description: |
46801
46888
  Reply to a first-level TikTok ad comment. Requires a TT_USER or CUSTOMIZED_USER identity with comment-management permission. Replies to replies are rejected. The response commentId identifies the new reply. This operation is not idempotent; do not blindly retry an uncertain response.
46802
46889
 
46890
+ Unknown identity and video item fields are resolved only when needed for this
46891
+ action, then persisted for reuse. Comment-specific fields take precedence.
46892
+ If TikTok no longer returns the ad needed to resolve identity, 404 ad_not_found
46893
+ directs you to check deletion or archival in TikTok Ads Manager. Listing can
46894
+ still succeed. Unsupported or unavailable identity returns 403 feature_not_available.
46895
+ Denied access to ad details returns 403 insufficient_permissions with reconnect
46896
+ guidance and the upstream platformError.
46897
+
46803
46898
  Requires Ads access. The ad is resolved within the caller's accessible profiles.
46804
46899
  Before moderation, Zernio verifies that the comment belongs to this ad using
46805
46900
  TikTok's ad-group comment listing. The default search window is the last 30 days.
@@ -46839,9 +46934,9 @@ paths:
46839
46934
  '400': { $ref: '#/components/responses/BadRequest' }
46840
46935
  '401': { $ref: '#/components/responses/Unauthorized' }
46841
46936
  '403':
46842
- description: "Ads access or the required TikTok comment capability is unavailable."
46937
+ description: "Ads access or supported identity is unavailable (feature_not_available), or TikTok denies ad-detail access or comment-management permission (insufficient_permissions). Grant permission and reconnect the TikTok Ads account before retrying."
46843
46938
  '404':
46844
- description: "Ad is inaccessible or the comment was not found on this ad in the selected date window."
46939
+ description: "Ad is inaccessible or unavailable on TikTok for identity resolution (ad_not_found), or the comment was not found on this ad in the selected date window (resource_not_found)."
46845
46940
  '422':
46846
46941
  description: "TikTok Ads connection is unavailable."
46847
46942
  '501':
@@ -46857,7 +46952,7 @@ paths:
46857
46952
  x-resource-group: "engagement"
46858
46953
  x-platforms: ["tiktok"]
46859
46954
  description: |
46860
- Hide or restore a TikTok ad comment. Send hidden=true to hide it or hidden=false to make it public again.
46955
+ Hide or restore a TikTok ad comment. Send hidden=true to hide it or hidden=false to make it public again. Identity and video item ID are not required; no identity lookup is performed.
46861
46956
 
46862
46957
  Requires Ads access. The ad is resolved within the caller's accessible profiles.
46863
46958
  Before moderation, Zernio verifies that the comment belongs to this ad using
@@ -46919,6 +47014,14 @@ paths:
46919
47014
  description: |
46920
47015
  Delete your own TikTok ad comment or reply. TikTok must return can_delete=true for the comment. Other users' comments can be hidden instead.
46921
47016
 
47017
+ Unknown identity and video item fields are resolved only when needed for this
47018
+ action, then persisted for reuse. Comment-specific fields take precedence.
47019
+ If TikTok no longer returns the ad needed to resolve identity, 404 ad_not_found
47020
+ directs you to check deletion or archival in TikTok Ads Manager. Listing can
47021
+ still succeed. Unsupported or unavailable identity returns 403 feature_not_available.
47022
+ Denied access to ad details returns 403 insufficient_permissions with reconnect
47023
+ guidance and the upstream platformError.
47024
+
46922
47025
  Requires Ads access. The ad is resolved within the caller's accessible profiles.
46923
47026
  Before moderation, Zernio verifies that the comment belongs to this ad using
46924
47027
  TikTok's ad-group comment listing. The default search window is the last 30 days.
@@ -46948,9 +47051,9 @@ paths:
46948
47051
  '400': { $ref: '#/components/responses/BadRequest' }
46949
47052
  '401': { $ref: '#/components/responses/Unauthorized' }
46950
47053
  '403':
46951
- description: "Ads access or the required TikTok comment capability is unavailable."
47054
+ description: "Ads access, own-comment deletion or supported identity is unavailable (feature_not_available), or TikTok denies ad-detail access (insufficient_permissions)."
46952
47055
  '404':
46953
- description: "Ad is inaccessible or the comment was not found on this ad in the selected date window."
47056
+ description: "Ad is inaccessible or unavailable on TikTok for identity resolution (ad_not_found), or the comment was not found on this ad in the selected date window (resource_not_found)."
46954
47057
  '422':
46955
47058
  description: "TikTok Ads connection is unavailable."
46956
47059
  '501':
@@ -46976,6 +47079,7 @@ paths:
46976
47079
  parameters:
46977
47080
  - { name: accountId, in: query, required: true, schema: { type: string }, description: ID of the `tiktokads` (or parent `tiktok` posting) SocialAccount }
46978
47081
  responses:
47082
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
46979
47083
  '200':
46980
47084
  description: Business centers
46981
47085
  content:
@@ -46988,7 +47092,8 @@ paths:
46988
47092
  items: { $ref: '#/components/schemas/BusinessCenter' }
46989
47093
  '400': { $ref: '#/components/responses/BadRequest' }
46990
47094
  '401': { $ref: '#/components/responses/Unauthorized' }
46991
- '404': { description: TikTok account not found }
47095
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
47096
+
46992
47097
  '422': { description: TikTok Ads not connected }
46993
47098
 
46994
47099
  /v1/ads/activity:
@@ -47015,6 +47120,8 @@ paths:
47015
47120
  - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 200, default: 50 }, description: Rows per page }
47016
47121
  - { name: after, in: query, schema: { type: string }, description: "Cursor from paging.after of the previous page." }
47017
47122
  responses:
47123
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
47124
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
47018
47125
  '200':
47019
47126
  description: Activity rows (raw Meta shape)
47020
47127
  content:
@@ -47040,7 +47147,7 @@ paths:
47040
47147
  operationId: createRfPrediction
47041
47148
  tags: ["Reach and Frequency"]
47042
47149
  x-platforms: ["meta"]
47043
- summary: Create a Reach & Frequency prediction
47150
+ summary: 'Create reach-frequency prediction'
47044
47151
  description: |-
47045
47152
  Creates an R&F prediction. This is a QUOTE, nothing is bought and no ad entities are created.
47046
47153
  Provide a date range plus exactly one of `budgetAmount` (Meta predicts reach) or `reach`
@@ -47073,6 +47180,8 @@ paths:
47073
47180
  targeting: { type: object, description: "Canonical camelCase TargetingSpec (same shape as /v1/ads/create's `targeting`). Defaults to countries: [US]." }
47074
47181
  placements: { type: object, description: "Meta placements object (same shape as /v1/ads/create's `placements`)." }
47075
47182
  responses:
47183
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
47184
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
47076
47185
  '201':
47077
47186
  description: Prediction created (usually ready within seconds)
47078
47187
  content:
@@ -47094,7 +47203,7 @@ paths:
47094
47203
  operationId: getRfPrediction
47095
47204
  tags: ["Reach and Frequency"]
47096
47205
  x-platforms: ["meta"]
47097
- summary: Read a Reach & Frequency prediction
47206
+ summary: 'Get reach-frequency prediction'
47098
47207
  security:
47099
47208
  - bearerAuth: []
47100
47209
  parameters:
@@ -47102,6 +47211,8 @@ paths:
47102
47211
  - { name: accountId, in: query, required: true, schema: { type: string } }
47103
47212
  - { name: adAccountId, in: query, required: true, schema: { type: string } }
47104
47213
  responses:
47214
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
47215
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
47105
47216
  '200':
47106
47217
  description: Prediction status and estimates
47107
47218
  content:
@@ -47120,7 +47231,7 @@ paths:
47120
47231
  operationId: cancelRfReservation
47121
47232
  tags: ["Reach and Frequency"]
47122
47233
  x-platforms: ["meta"]
47123
- summary: Cancel a Reach & Frequency reservation
47234
+ summary: 'Cancel reach-frequency booking'
47124
47235
  description: Releases a RESERVATION's locked price and inventory. Unreserved predictions expire on their own.
47125
47236
  security:
47126
47237
  - bearerAuth: []
@@ -47129,6 +47240,8 @@ paths:
47129
47240
  - { name: accountId, in: query, required: true, schema: { type: string } }
47130
47241
  - { name: adAccountId, in: query, required: true, schema: { type: string } }
47131
47242
  responses:
47243
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
47244
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
47132
47245
  '200':
47133
47246
  description: Reservation cancelled
47134
47247
  '400': { description: "Invalid input, or Meta rejected the cancel" }
@@ -47141,7 +47254,7 @@ paths:
47141
47254
  operationId: reserveRfPrediction
47142
47255
  tags: ["Reach and Frequency"]
47143
47256
  x-platforms: ["meta"]
47144
- summary: Reserve a Reach & Frequency prediction
47257
+ summary: 'Reserve reach-frequency inventory'
47145
47258
  description: |-
47146
47259
  Locks the quoted price + inventory until the returned `expiresAt` and mints a NEW
47147
47260
  prediction id. Pass that RESERVED id (not the original) as `rfPredictionId` on
@@ -47161,6 +47274,8 @@ paths:
47161
47274
  accountId: { type: string }
47162
47275
  adAccountId: { type: string }
47163
47276
  responses:
47277
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
47278
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
47164
47279
  '201':
47165
47280
  description: Reserved; `prediction.predictionId` is the new RESERVED id
47166
47281
  content:
@@ -47194,6 +47309,8 @@ paths:
47194
47309
  - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 100, default: 25 }, description: Rows per page }
47195
47310
  - { name: after, in: query, schema: { type: string }, description: "Cursor from paging.after of the previous page." }
47196
47311
  responses:
47312
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
47313
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
47197
47314
  '200':
47198
47315
  description: Ad studies (raw Meta shape)
47199
47316
  content:
@@ -47227,6 +47344,7 @@ paths:
47227
47344
  - { name: accountId, in: query, required: true, schema: { type: string }, description: "Zernio Meta Ads or Facebook SocialAccount ID." }
47228
47345
  - { name: adAccountId, in: query, required: true, schema: { type: string, pattern: '^act_[0-9]+$' }, description: "Meta ad account ID including the act_ prefix." }
47229
47346
  responses:
47347
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
47230
47348
  '200':
47231
47349
  description: "Instagram identities and Page linkage."
47232
47350
  content:
@@ -47273,7 +47391,8 @@ paths:
47273
47391
  '400': { $ref: '#/components/responses/BadRequest' }
47274
47392
  '401': { $ref: '#/components/responses/Unauthorized' }
47275
47393
  '403': { description: "The account or Meta asset is not accessible." }
47276
- '404': { $ref: '#/components/responses/NotFound' }
47394
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
47395
+
47277
47396
  '501': { description: "Only supported on Meta Ads and Facebook accounts." }
47278
47397
 
47279
47398
  /v1/ads/advertisable-applications:
@@ -47290,6 +47409,7 @@ paths:
47290
47409
  - { name: accountId, in: query, required: true, schema: { type: string }, description: "Zernio Meta Ads or Facebook SocialAccount ID." }
47291
47410
  - { name: adAccountId, in: query, required: true, schema: { type: string, pattern: '^act_[0-9]+$' }, description: "Meta ad account ID including the act_ prefix." }
47292
47411
  responses:
47412
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
47293
47413
  '200':
47294
47414
  description: "Applications available for promotion."
47295
47415
  content:
@@ -47323,7 +47443,8 @@ paths:
47323
47443
  '400': { $ref: '#/components/responses/BadRequest' }
47324
47444
  '401': { $ref: '#/components/responses/Unauthorized' }
47325
47445
  '403': { description: "The account or Meta asset is not accessible." }
47326
- '404': { $ref: '#/components/responses/NotFound' }
47446
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
47447
+
47327
47448
  '501': { description: "Only supported on Meta Ads and Facebook accounts." }
47328
47449
 
47329
47450
  /v1/ads/ios-fourteen-campaign-limits:
@@ -47341,6 +47462,7 @@ paths:
47341
47462
  - { name: adAccountId, in: query, required: true, schema: { type: string, pattern: '^act_[0-9]+$' }, description: "Meta ad account ID including the act_ prefix." }
47342
47463
  - { name: applicationId, in: query, required: true, schema: { type: string, pattern: '^[0-9]+$' }, description: "Meta application ID from advertisable-applications." }
47343
47464
  responses:
47465
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
47344
47466
  '200':
47345
47467
  description: "Application campaign limits."
47346
47468
  content:
@@ -47363,7 +47485,8 @@ paths:
47363
47485
  '400': { $ref: '#/components/responses/BadRequest' }
47364
47486
  '401': { $ref: '#/components/responses/Unauthorized' }
47365
47487
  '403': { description: "The account or Meta asset is not accessible." }
47366
- '404': { $ref: '#/components/responses/NotFound' }
47488
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
47489
+
47367
47490
  '501': { description: "Only supported on Meta Ads and Facebook accounts." }
47368
47491
 
47369
47492
  /v1/ads/businesses:
@@ -47385,6 +47508,8 @@ paths:
47385
47508
  - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 100, default: 25 }, description: Rows per page }
47386
47509
  - { name: after, in: query, schema: { type: string }, description: "Cursor from paging.after of the previous page." }
47387
47510
  responses:
47511
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
47512
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
47388
47513
  '200':
47389
47514
  description: Businesses (raw Meta shape)
47390
47515
  content:
@@ -47421,6 +47546,8 @@ paths:
47421
47546
  - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 100, default: 25 }, description: Rows per page }
47422
47547
  - { name: after, in: query, schema: { type: string }, description: "Cursor from paging.after of the previous page." }
47423
47548
  responses:
47549
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
47550
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
47424
47551
  '200':
47425
47552
  description: Ad labels (raw Meta shape)
47426
47553
  content:
@@ -47446,7 +47573,7 @@ paths:
47446
47573
  operationId: listHighDemandPeriods
47447
47574
  tags: ["Ad Accounts"]
47448
47575
  x-platforms: ["meta"]
47449
- summary: High demand periods / budget schedules
47576
+ summary: 'List high-demand periods'
47450
47577
  description: |-
47451
47578
  Scheduled budget increases (Meta's budget-scheduling API). The Graph edge lives on the
47452
47579
  campaign and ad-set nodes only, so exactly one of `campaignId` / `adSetId` (platform
@@ -47461,6 +47588,8 @@ paths:
47461
47588
  - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 100, default: 25 }, description: Rows per page }
47462
47589
  - { name: after, in: query, schema: { type: string }, description: "Cursor from paging.after of the previous page." }
47463
47590
  responses:
47591
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
47592
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
47464
47593
  '200':
47465
47594
  description: Budget schedules (raw Meta shape)
47466
47595
  content:
@@ -47515,6 +47644,8 @@ paths:
47515
47644
  recurrenceType: { type: string, enum: [ONE_TIME, WEEKLY, MONTHLY] }
47516
47645
  currency: { type: string, description: "Ad account currency, for the ABSOLUTE minor-unit conversion. Ignored for MULTIPLIER." }
47517
47646
  responses:
47647
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
47648
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
47518
47649
  '201':
47519
47650
  description: Budget schedule created
47520
47651
  content:
@@ -47550,6 +47681,8 @@ paths:
47550
47681
  - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 100, default: 25 }, description: Rows per page }
47551
47682
  - { name: after, in: query, schema: { type: string }, description: "Cursor from paging.after of the previous page." }
47552
47683
  responses:
47684
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
47685
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
47553
47686
  '200':
47554
47687
  description: Creatives (raw Meta shape)
47555
47688
  content:
@@ -47635,6 +47768,8 @@ paths:
47635
47768
  promotion: { type: PERCENTAGE_OFF, value: 20, code: SAVE20 }
47636
47769
  creativeFeatures: { auto_promotion_tag: OPT_OUT }
47637
47770
  responses:
47771
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
47772
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
47638
47773
  '201':
47639
47774
  description: Creative created
47640
47775
  content:
@@ -47674,6 +47809,8 @@ paths:
47674
47809
  - { name: accountId, in: query, required: true, schema: { type: string }, description: "Zernio SocialAccount id (posting or ads variant) used to resolve the Meta token." }
47675
47810
  - { name: fields, in: query, schema: { type: string }, description: "Comma-separated Graph field override (supports nested {} projections)." }
47676
47811
  responses:
47812
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
47813
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
47677
47814
  '200':
47678
47815
  description: Creative details
47679
47816
  content:
@@ -47710,6 +47847,8 @@ paths:
47710
47847
  accountId: { type: string, description: "Zernio SocialAccount id (posting or ads variant); its platform decides where the campaign is created." }
47711
47848
  name: { type: string, maxLength: 255 }
47712
47849
  responses:
47850
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
47851
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
47713
47852
  '200':
47714
47853
  description: Creative renamed
47715
47854
  content:
@@ -47738,6 +47877,8 @@ paths:
47738
47877
  - { name: creativeId, in: path, required: true, schema: { type: string }, description: Platform creative id }
47739
47878
  - { name: accountId, in: query, required: true, schema: { type: string }, description: "Zernio SocialAccount id (posting or ads variant) used to resolve the Meta token." }
47740
47879
  responses:
47880
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
47881
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
47741
47882
  '200':
47742
47883
  description: Creative deleted
47743
47884
  content:
@@ -47784,6 +47925,8 @@ paths:
47784
47925
  - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 100, default: 25 }, description: Rows per page }
47785
47926
  - { name: after, in: query, schema: { type: string }, description: "Cursor from paging.after of the previous page. Meta does not document paging on this edge; `after` comes back null when it omits cursors." }
47786
47927
  responses:
47928
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
47929
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
47787
47930
  '200':
47788
47931
  description: Value rule sets
47789
47932
  content:
@@ -47860,6 +48003,8 @@ paths:
47860
48003
  description: "Evaluated in order; the first matching rule wins."
47861
48004
  items: { $ref: '#/components/schemas/ValueRule' }
47862
48005
  responses:
48006
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
48007
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
47863
48008
  '201':
47864
48009
  description: Value rule set created
47865
48010
  content:
@@ -47894,6 +48039,8 @@ paths:
47894
48039
  - { name: valueRuleSetId, in: path, required: true, schema: { type: string }, description: "Platform value rule set id." }
47895
48040
  - { name: accountId, in: query, required: true, schema: { type: string }, description: "Zernio SocialAccount id (posting or ads variant) used to resolve the Meta token." }
47896
48041
  responses:
48042
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
48043
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
47897
48044
  '200':
47898
48045
  description: Value rule set
47899
48046
  content:
@@ -47950,6 +48097,8 @@ paths:
47950
48097
  description: "The COMPLETE rule list. Omitting a rule deletes it on Meta."
47951
48098
  items: { $ref: '#/components/schemas/ValueRule' }
47952
48099
  responses:
48100
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
48101
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
47953
48102
  '200':
47954
48103
  description: Value rule set replaced
47955
48104
  content:
@@ -47984,6 +48133,8 @@ paths:
47984
48133
  - { name: valueRuleSetId, in: path, required: true, schema: { type: string }, description: "Platform value rule set id." }
47985
48134
  - { name: accountId, in: query, required: true, schema: { type: string }, description: "Zernio SocialAccount id (posting or ads variant) used to resolve the Meta token." }
47986
48135
  responses:
48136
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
48137
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
47987
48138
  '200':
47988
48139
  description: Value rule set deleted
47989
48140
  content:
@@ -48080,10 +48231,10 @@ paths:
48080
48231
  $ref: "#/components/responses/Unauthorized"
48081
48232
  "403":
48082
48233
  description: "Ads access and permission to the selected account are required."
48083
- "404":
48084
- $ref: "#/components/responses/NotFound"
48234
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
48235
+
48085
48236
  "409":
48086
- description: "Ambiguous campaign or account selection. Use a profile-scoped key. A list still attached to a campaign may also be rejected by Google."
48237
+ description: 'Ambiguous campaign or account selection. Use a profile-scoped key. A list still attached to a campaign may also be rejected by Google. The account may also be inactive or need reconnection (code ads_connection_required). Reconnect it and read GET /v1/accounts for its current ID before retrying.'
48087
48238
  "422":
48088
48239
  description: "Google Ads connection is missing or unavailable."
48089
48240
  "429":
@@ -48184,10 +48335,10 @@ paths:
48184
48335
  $ref: "#/components/responses/Unauthorized"
48185
48336
  "403":
48186
48337
  description: "Ads access and permission to the selected account are required."
48187
- "404":
48188
- $ref: "#/components/responses/NotFound"
48338
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
48339
+
48189
48340
  "409":
48190
- description: "Ambiguous campaign or account selection. Use a profile-scoped key. A list still attached to a campaign may also be rejected by Google."
48341
+ description: 'Ambiguous campaign or account selection. Use a profile-scoped key. A list still attached to a campaign may also be rejected by Google. The account may also be inactive or need reconnection (code ads_connection_required). Reconnect it and read GET /v1/accounts for its current ID before retrying.'
48191
48342
  "422":
48192
48343
  description: "Google Ads connection is missing or unavailable."
48193
48344
  "429":
@@ -48296,10 +48447,10 @@ paths:
48296
48447
  $ref: "#/components/responses/Unauthorized"
48297
48448
  "403":
48298
48449
  description: "Ads access and permission to the selected account are required."
48299
- "404":
48300
- $ref: "#/components/responses/NotFound"
48450
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
48451
+
48301
48452
  "409":
48302
- description: "Ambiguous campaign or account selection. Use a profile-scoped key. A list still attached to a campaign may also be rejected by Google."
48453
+ description: 'Ambiguous campaign or account selection. Use a profile-scoped key. A list still attached to a campaign may also be rejected by Google. The account may also be inactive or need reconnection (code ads_connection_required). Reconnect it and read GET /v1/accounts for its current ID before retrying.'
48303
48454
  "422":
48304
48455
  description: "Google Ads connection is missing or unavailable."
48305
48456
  "429":
@@ -48388,10 +48539,10 @@ paths:
48388
48539
  $ref: "#/components/responses/Unauthorized"
48389
48540
  "403":
48390
48541
  description: "Ads access and permission to the selected account are required."
48391
- "404":
48392
- $ref: "#/components/responses/NotFound"
48542
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
48543
+
48393
48544
  "409":
48394
- description: "Ambiguous campaign or account selection. Use a profile-scoped key. A list still attached to a campaign may also be rejected by Google."
48545
+ description: 'Ambiguous campaign or account selection. Use a profile-scoped key. A list still attached to a campaign may also be rejected by Google. The account may also be inactive or need reconnection (code ads_connection_required). Reconnect it and read GET /v1/accounts for its current ID before retrying.'
48395
48546
  "422":
48396
48547
  description: "Google Ads connection is missing or unavailable."
48397
48548
  "429":
@@ -48469,10 +48620,10 @@ paths:
48469
48620
  $ref: "#/components/responses/Unauthorized"
48470
48621
  "403":
48471
48622
  description: "Ads access and permission to the selected account are required."
48472
- "404":
48473
- $ref: "#/components/responses/NotFound"
48623
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
48624
+
48474
48625
  "409":
48475
- description: "Ambiguous campaign or account selection. Use a profile-scoped key. A list still attached to a campaign may also be rejected by Google."
48626
+ description: 'Ambiguous campaign or account selection. Use a profile-scoped key. A list still attached to a campaign may also be rejected by Google. The account may also be inactive or need reconnection (code ads_connection_required). Reconnect it and read GET /v1/accounts for its current ID before retrying.'
48476
48627
  "422":
48477
48628
  description: "Google Ads connection is missing or unavailable."
48478
48629
  "429":
@@ -48571,10 +48722,10 @@ paths:
48571
48722
  $ref: "#/components/responses/Unauthorized"
48572
48723
  "403":
48573
48724
  description: "Ads access and permission to the selected account are required."
48574
- "404":
48575
- $ref: "#/components/responses/NotFound"
48725
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
48726
+
48576
48727
  "409":
48577
- description: "Ambiguous campaign or account selection. Use a profile-scoped key. A list still attached to a campaign may also be rejected by Google."
48728
+ description: 'Ambiguous campaign or account selection. Use a profile-scoped key. A list still attached to a campaign may also be rejected by Google. The account may also be inactive or need reconnection (code ads_connection_required). Reconnect it and read GET /v1/accounts for its current ID before retrying.'
48578
48729
  "422":
48579
48730
  description: "Google Ads connection is missing or unavailable."
48580
48731
  "429":
@@ -48656,10 +48807,10 @@ paths:
48656
48807
  $ref: "#/components/responses/Unauthorized"
48657
48808
  "403":
48658
48809
  description: "Ads access and permission to the selected account are required."
48659
- "404":
48660
- $ref: "#/components/responses/NotFound"
48810
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
48811
+
48661
48812
  "409":
48662
- description: "Ambiguous campaign or account selection. Use a profile-scoped key. A list still attached to a campaign may also be rejected by Google."
48813
+ description: 'Ambiguous campaign or account selection. Use a profile-scoped key. A list still attached to a campaign may also be rejected by Google. The account may also be inactive or need reconnection (code ads_connection_required). Reconnect it and read GET /v1/accounts for its current ID before retrying.'
48663
48814
  "422":
48664
48815
  description: "Google Ads connection is missing or unavailable."
48665
48816
  "429":
@@ -48746,10 +48897,10 @@ paths:
48746
48897
  $ref: "#/components/responses/Unauthorized"
48747
48898
  "403":
48748
48899
  description: "Ads access and permission to the selected account are required."
48749
- "404":
48750
- $ref: "#/components/responses/NotFound"
48900
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
48901
+
48751
48902
  "409":
48752
- description: "Ambiguous campaign or account selection. Use a profile-scoped key. A list still attached to a campaign may also be rejected by Google."
48903
+ description: 'Ambiguous campaign or account selection. Use a profile-scoped key. A list still attached to a campaign may also be rejected by Google. The account may also be inactive or need reconnection (code ads_connection_required). Reconnect it and read GET /v1/accounts for its current ID before retrying.'
48753
48904
  "422":
48754
48905
  description: "Google Ads connection is missing or unavailable."
48755
48906
  "429":
@@ -48786,6 +48937,7 @@ paths:
48786
48937
  pattern: ^\d+$
48787
48938
  description: "Google customer id without dashes. Required when the connection has multiple customers."
48788
48939
  responses:
48940
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
48789
48941
  '200':
48790
48942
  description: "Assets returned."
48791
48943
  content:
@@ -48821,8 +48973,8 @@ paths:
48821
48973
  $ref: '#/components/responses/Unauthorized'
48822
48974
  '403':
48823
48975
  description: "Ads access is required."
48824
- '404':
48825
- $ref: '#/components/responses/NotFound'
48976
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
48977
+
48826
48978
  '429':
48827
48979
  description: "Google Ads operations budget or platform quota exhausted."
48828
48980
  '501':
@@ -48870,6 +49022,7 @@ paths:
48870
49022
  callouts:
48871
49023
  - Fast setup
48872
49024
  responses:
49025
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
48873
49026
  '201':
48874
49027
  description: "Assets created and attached."
48875
49028
  content:
@@ -48894,8 +49047,8 @@ paths:
48894
49047
  $ref: '#/components/responses/Unauthorized'
48895
49048
  '403':
48896
49049
  description: "Ads access is required."
48897
- '404':
48898
- $ref: '#/components/responses/NotFound'
49050
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
49051
+
48899
49052
  '429':
48900
49053
  description: "Google Ads operations budget or platform quota exhausted."
48901
49054
  '501':
@@ -48963,6 +49116,7 @@ paths:
48963
49116
  calloutAsset:
48964
49117
  calloutText: Simple integration
48965
49118
  responses:
49119
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
48966
49120
  '200':
48967
49121
  description: "Assets returned."
48968
49122
  content:
@@ -48980,8 +49134,8 @@ paths:
48980
49134
  $ref: '#/components/responses/Unauthorized'
48981
49135
  '403':
48982
49136
  description: "Ads access is required."
48983
- '404':
48984
- $ref: '#/components/responses/NotFound'
49137
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
49138
+
48985
49139
  '429':
48986
49140
  description: "Google Ads operations budget or platform quota exhausted."
48987
49141
  '501':
@@ -49024,6 +49178,7 @@ paths:
49024
49178
  customerId: '1234567890'
49025
49179
  assetId: '123'
49026
49180
  responses:
49181
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
49027
49182
  '200':
49028
49183
  description: "Assets returned."
49029
49184
  content:
@@ -49041,8 +49196,8 @@ paths:
49041
49196
  $ref: '#/components/responses/Unauthorized'
49042
49197
  '403':
49043
49198
  description: "Ads access is required."
49044
- '404':
49045
- $ref: '#/components/responses/NotFound'
49199
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
49200
+
49046
49201
  '429':
49047
49202
  description: "Google Ads operations budget or platform quota exhausted."
49048
49203
  '501':
@@ -49076,6 +49231,7 @@ paths:
49076
49231
  pattern: ^\d+$
49077
49232
  description: "Google customer id without dashes. Required when the connection has multiple customers."
49078
49233
  responses:
49234
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
49079
49235
  '200':
49080
49236
  description: "Assets returned."
49081
49237
  content:
@@ -49122,8 +49278,8 @@ paths:
49122
49278
  $ref: '#/components/responses/Unauthorized'
49123
49279
  '403':
49124
49280
  description: "Ads access is required."
49125
- '404':
49126
- $ref: '#/components/responses/NotFound'
49281
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
49282
+
49127
49283
  '429':
49128
49284
  description: "Google Ads operations budget or platform quota exhausted."
49129
49285
  '501':
@@ -49170,6 +49326,7 @@ paths:
49170
49326
  - text: Pricing
49171
49327
  linkUrl: https://zernio.com/pricing
49172
49328
  responses:
49329
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
49173
49330
  '201':
49174
49331
  description: "Assets created and attached."
49175
49332
  content:
@@ -49207,8 +49364,8 @@ paths:
49207
49364
  $ref: '#/components/responses/Unauthorized'
49208
49365
  '403':
49209
49366
  description: "Ads access is required."
49210
- '404':
49211
- $ref: '#/components/responses/NotFound'
49367
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
49368
+
49212
49369
  '429':
49213
49370
  description: "Google Ads operations budget or platform quota exhausted."
49214
49371
  '501':
@@ -49293,6 +49450,7 @@ paths:
49293
49450
  finalUrls:
49294
49451
  - https://zernio.com/pricing
49295
49452
  responses:
49453
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
49296
49454
  '200':
49297
49455
  description: "Assets returned."
49298
49456
  content:
@@ -49310,8 +49468,8 @@ paths:
49310
49468
  $ref: '#/components/responses/Unauthorized'
49311
49469
  '403':
49312
49470
  description: "Ads access is required."
49313
- '404':
49314
- $ref: '#/components/responses/NotFound'
49471
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
49472
+
49315
49473
  '429':
49316
49474
  description: "Google Ads operations budget or platform quota exhausted."
49317
49475
  '501':
@@ -49354,6 +49512,7 @@ paths:
49354
49512
  customerId: '1234567890'
49355
49513
  assetId: '123'
49356
49514
  responses:
49515
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
49357
49516
  '200':
49358
49517
  description: "Assets returned."
49359
49518
  content:
@@ -49371,8 +49530,8 @@ paths:
49371
49530
  $ref: '#/components/responses/Unauthorized'
49372
49531
  '403':
49373
49532
  description: "Ads access is required."
49374
- '404':
49375
- $ref: '#/components/responses/NotFound'
49533
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
49534
+
49376
49535
  '429':
49377
49536
  description: "Google Ads operations budget or platform quota exhausted."
49378
49537
  '501':
@@ -49406,6 +49565,7 @@ paths:
49406
49565
  pattern: ^\d+$
49407
49566
  description: "Google customer id without dashes. Required when the connection has multiple customers."
49408
49567
  responses:
49568
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
49409
49569
  '200':
49410
49570
  description: "Assets returned."
49411
49571
  content:
@@ -49449,8 +49609,8 @@ paths:
49449
49609
  $ref: '#/components/responses/Unauthorized'
49450
49610
  '403':
49451
49611
  description: "Ads access is required."
49452
- '404':
49453
- $ref: '#/components/responses/NotFound'
49612
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
49613
+
49454
49614
  '429':
49455
49615
  description: "Google Ads operations budget or platform quota exhausted."
49456
49616
  '501':
@@ -49500,6 +49660,7 @@ paths:
49500
49660
  - Analytics
49501
49661
  - Messaging
49502
49662
  responses:
49663
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
49503
49664
  '201':
49504
49665
  description: "Assets created and attached."
49505
49666
  content:
@@ -49546,8 +49707,8 @@ paths:
49546
49707
  $ref: '#/components/responses/Unauthorized'
49547
49708
  '403':
49548
49709
  description: "Ads access is required."
49549
- '404':
49550
- $ref: '#/components/responses/NotFound'
49710
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
49711
+
49551
49712
  '429':
49552
49713
  description: "Google Ads operations budget or platform quota exhausted."
49553
49714
  '501':
@@ -49612,6 +49773,7 @@ paths:
49612
49773
  - Reporting
49613
49774
  - Messaging
49614
49775
  responses:
49776
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
49615
49777
  '200':
49616
49778
  description: "Assets returned."
49617
49779
  content:
@@ -49629,8 +49791,8 @@ paths:
49629
49791
  $ref: '#/components/responses/Unauthorized'
49630
49792
  '403':
49631
49793
  description: "Ads access is required."
49632
- '404':
49633
- $ref: '#/components/responses/NotFound'
49794
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
49795
+
49634
49796
  '429':
49635
49797
  description: "Google Ads operations budget or platform quota exhausted."
49636
49798
  '501':
@@ -49673,6 +49835,7 @@ paths:
49673
49835
  customerId: '1234567890'
49674
49836
  assetId: '123'
49675
49837
  responses:
49838
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
49676
49839
  '200':
49677
49840
  description: "Assets returned."
49678
49841
  content:
@@ -49690,8 +49853,8 @@ paths:
49690
49853
  $ref: '#/components/responses/Unauthorized'
49691
49854
  '403':
49692
49855
  description: "Ads access is required."
49693
- '404':
49694
- $ref: '#/components/responses/NotFound'
49856
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
49857
+
49695
49858
  '429':
49696
49859
  description: "Google Ads operations budget or platform quota exhausted."
49697
49860
  '501':
@@ -49714,6 +49877,8 @@ paths:
49714
49877
  - { name: accountId, in: query, required: true, schema: { type: string }, description: "Zernio SocialAccount id (posting or ads variant) used to resolve the Meta token." }
49715
49878
  - { name: adAccountId, in: query, required: true, schema: { type: string }, description: "Meta ad account id (act_<n>)." }
49716
49879
  responses:
49880
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
49881
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
49717
49882
  '200':
49718
49883
  description: Account finances
49719
49884
  content:
@@ -49804,6 +49969,7 @@ paths:
49804
49969
  currency: "EUR"
49805
49970
  timezoneId: 1
49806
49971
  responses:
49972
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
49807
49973
  '201':
49808
49974
  description: "Ad account created. Check connectionUpdated and payment instructions."
49809
49975
  content:
@@ -49845,7 +50011,8 @@ paths:
49845
50011
  content:
49846
50012
  application/json:
49847
50013
  schema: { $ref: '#/components/schemas/ErrorResponse' }
49848
- '404': { $ref: '#/components/responses/NotFound' }
50014
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
50015
+
49849
50016
  '502':
49850
50017
  description: "Creation outcome unknown. Check Ads Manager before repeating this non-idempotent request."
49851
50018
  content:
@@ -49885,6 +50052,9 @@ paths:
49885
50052
  - { name: adAccountId, in: query, required: false, schema: { type: string }, description: "Filter response to a single platform ad account ID (e.g. `act_123` for Meta, advertiser_id for TikTok). Returns at most one item." }
49886
50053
  - { name: limit, in: query, required: false, schema: { type: integer, minimum: 1, maximum: 1000 }, description: "Clamp the returned `accounts[]` length. Useful for typeahead pickers on agency tokens with hundreds of advertisers." }
49887
50054
  responses:
50055
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
50056
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
50057
+ '400': { $ref: '#/components/responses/BadRequest' }
49888
50058
  '200':
49889
50059
  description: Ad accounts
49890
50060
  content:
@@ -49977,6 +50147,7 @@ paths:
49977
50147
  defaultDsaBeneficiary: { type: string, maxLength: 100, description: "Legal entity benefiting from ads on this ad account" }
49978
50148
  defaultDsaPayor: { type: string, maxLength: 100, description: "Legal entity paying for ads on this ad account. Defaults to defaultDsaBeneficiary when omitted." }
49979
50149
  responses:
50150
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
49980
50151
  '200':
49981
50152
  description: DSA defaults updated (re-read from Meta after the write)
49982
50153
  content:
@@ -49993,9 +50164,7 @@ paths:
49993
50164
  '400':
49994
50165
  description: Unsupported platform (non-Meta account) or invalid adAccountId
49995
50166
  '401': { $ref: '#/components/responses/Unauthorized' }
49996
- '404':
49997
- description: Account not found
49998
-
50167
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
49999
50168
  /v1/ads/dsa-defaults:
50000
50169
  get:
50001
50170
  x-resource-group: "ads"
@@ -50013,6 +50182,7 @@ paths:
50013
50182
  - { name: accountId, in: query, required: true, schema: { type: string }, description: "Account ID (metaads, or a facebook/instagram posting account)" }
50014
50183
  - { name: adAccountId, in: query, required: true, schema: { type: string }, description: "Meta ad account ID (act_...)" }
50015
50184
  responses:
50185
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
50016
50186
  '200':
50017
50187
  description: Current DSA defaults (empty object when none are set)
50018
50188
  content:
@@ -50029,16 +50199,14 @@ paths:
50029
50199
  '400':
50030
50200
  description: Non-Meta adAccountId
50031
50201
  '401': { $ref: '#/components/responses/Unauthorized' }
50032
- '404':
50033
- description: Account not found
50034
-
50202
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
50035
50203
  /v1/ads/dsa-recommendations:
50036
50204
  get:
50037
50205
  x-resource-group: "ads"
50038
50206
  operationId: getDsaRecommendations
50039
50207
  tags: ["Ad Accounts"]
50040
50208
  x-platforms: ["meta"]
50041
- summary: List DSA beneficiary/payor suggestions
50209
+ summary: 'Get DSA recommendations'
50042
50210
  description: |
50043
50211
  Returns Meta's suggested beneficiary/payor names for an ad account, derived by Meta
50044
50212
  from the account's recent activity. Useful for prefilling `dsaBeneficiary`/`dsaPayor`
@@ -50054,6 +50222,7 @@ paths:
50054
50222
  - { name: accountId, in: query, required: true, schema: { type: string }, description: "Account ID (metaads, or a facebook/instagram posting account)" }
50055
50223
  - { name: adAccountId, in: query, required: true, schema: { type: string }, description: "Meta ad account ID (act_...)" }
50056
50224
  responses:
50225
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
50057
50226
  '200':
50058
50227
  description: Suggested DSA strings (may be empty when Meta has no recommendations)
50059
50228
  content:
@@ -50068,9 +50237,7 @@ paths:
50068
50237
  '400':
50069
50238
  description: Non-Meta adAccountId
50070
50239
  '401': { $ref: '#/components/responses/Unauthorized' }
50071
- '404':
50072
- description: Account not found
50073
-
50240
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
50074
50241
  /v1/ads/boost:
50075
50242
  post:
50076
50243
  x-resource-group: "ads"
@@ -50403,6 +50570,7 @@ paths:
50403
50570
  budget: { amount: 2.61, type: daily }
50404
50571
  status: PAUSED
50405
50572
  responses:
50573
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
50406
50574
  '201':
50407
50575
  description: Ad created
50408
50576
  content:
@@ -50419,6 +50587,7 @@ paths:
50419
50587
  description: 'Ads access required. Legacy plans need the Ads add-on; included by default on usage-based plans. Also returned with code `ads_allowance_exceeded` when the team has no payment method on file and has reached the 500 free live ads: add a card to resume.'
50420
50588
  '409':
50421
50589
  description: |
50590
+ The account may also be inactive or need reconnection (code ads_connection_required). Reconnect it and read GET /v1/accounts for its current ID before retrying.
50422
50591
  An identical boost request is already in progress (with or without
50423
50592
  an Idempotency-Key). Wait for it to finish instead of retrying.
50424
50593
  '422':
@@ -51569,6 +51738,8 @@ paths:
51569
51738
  promotion: { type: PERCENTAGE_OFF, value: 20, code: SAVE20 }
51570
51739
  creativeFeatures: { auto_promotion_tag: OPT_OUT }
51571
51740
  responses:
51741
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
51742
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
51572
51743
  '200':
51573
51744
  description: 'validateOnly dry-run passed, nothing was created'
51574
51745
  content:
@@ -51931,6 +52102,8 @@ paths:
51931
52102
  - { name: cursor, in: query, schema: { type: string } }
51932
52103
  - { name: since, in: query, schema: { type: integer }, description: Unix seconds. }
51933
52104
  responses:
52105
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
52106
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
51934
52107
  '200':
51935
52108
  description: Leads for the form.
51936
52109
  content:
@@ -52021,6 +52194,8 @@ paths:
52021
52194
  imageBase64: { type: string, description: "Raw base64 image bytes, or a full data URL (the data:image/...;base64, prefix is stripped)." }
52022
52195
  filename: { type: string, description: "Optional filename shown in Meta's image library. Defaults to ad_image.jpg." }
52023
52196
  responses:
52197
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
52198
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
52024
52199
  '201':
52025
52200
  description: Image uploaded
52026
52201
  content:
@@ -52059,6 +52234,8 @@ paths:
52059
52234
  - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 100, default: 25 }, description: Rows per page }
52060
52235
  - { name: after, in: query, schema: { type: string }, description: "Cursor from paging.after of the previous page." }
52061
52236
  responses:
52237
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
52238
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
52062
52239
  '200':
52063
52240
  description: Ad images (raw Meta shape)
52064
52241
  content:
@@ -52114,6 +52291,8 @@ paths:
52114
52291
  videoBase64: { type: string, description: "Raw base64 video bytes, or a full data URL (the data:video/...;base64, prefix is stripped). Capped by Vercel's body limit (~4.5 MB payload). Provide exactly one of videoUrl or videoBase64." }
52115
52292
  filename: { type: string, description: "Optional filename shown alongside the upload session. Applied only when uploading via videoBase64." }
52116
52293
  responses:
52294
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
52295
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
52117
52296
  '201':
52118
52297
  description: Video uploaded and ready
52119
52298
  content:
@@ -52163,6 +52342,8 @@ paths:
52163
52342
  - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 100, default: 25 }, description: Rows per page }
52164
52343
  - { name: after, in: query, schema: { type: string }, description: "Cursor from paging.after of the previous page." }
52165
52344
  responses:
52345
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
52346
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
52166
52347
  '200':
52167
52348
  description: Ad videos (raw Meta shape)
52168
52349
  content:
@@ -52203,6 +52384,8 @@ paths:
52203
52384
  - { name: accountId, in: query, required: true, schema: { type: string }, description: "Zernio SocialAccount id (posting or ads variant) used to resolve the Meta token." }
52204
52385
  - { name: adAccountId, in: query, required: true, schema: { type: string }, description: "Meta ad account id (act_<n>) that owns the video." }
52205
52386
  responses:
52387
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
52388
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
52206
52389
  '200':
52207
52390
  description: Video deleted
52208
52391
  content:
@@ -52236,6 +52419,9 @@ paths:
52236
52419
  - { name: q, in: query, required: true, schema: { type: string }, description: Search query }
52237
52420
  - { name: accountId, in: query, required: true, schema: { type: string }, description: Account ID }
52238
52421
  responses:
52422
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
52423
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
52424
+ '400': { $ref: '#/components/responses/BadRequest' }
52239
52425
  '200':
52240
52426
  description: Matching interests
52241
52427
  content:
@@ -52343,6 +52529,7 @@ paths:
52343
52529
  - { name: countryCode, in: query, required: false, schema: { type: string, minLength: 2, maxLength: 2 }, description: "ISO 3166-1 alpha-2 country code (e.g. NL) to scope a geo search." }
52344
52530
  - { name: limit, in: query, required: false, schema: { type: integer, minimum: 1, maximum: 100, default: 25 }, description: "Maximum results to return." }
52345
52531
  responses:
52532
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
52346
52533
  '200':
52347
52534
  description: Matching targeting options (normalized)
52348
52535
  content:
@@ -52366,9 +52553,7 @@ paths:
52366
52553
  '401': { $ref: '#/components/responses/Unauthorized' }
52367
52554
  '403':
52368
52555
  description: Ads access required. Legacy plans need the Ads add-on; included by default on usage-based plans.
52369
- '404':
52370
- description: Account not found, or the platform does not support the requested dimension
52371
-
52556
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
52372
52557
  /v1/ads/library:
52373
52558
  get:
52374
52559
  x-resource-group: "ads"
@@ -52419,6 +52604,7 @@ paths:
52419
52604
  - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 100, default: 25 }, description: "Rows per page. LinkedIn accepts at most 25." }
52420
52605
  - { name: after, in: query, schema: { type: string }, description: "paging.after of the previous page." }
52421
52606
  responses:
52607
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
52422
52608
  '200':
52423
52609
  description: Archived ads (raw platform shape)
52424
52610
  content:
@@ -52477,7 +52663,8 @@ paths:
52477
52663
  '401': { $ref: '#/components/responses/Unauthorized' }
52478
52664
  '403':
52479
52665
  description: "Ads access required (legacy plans need the Ads add-on; included on usage-based plans), or `payment_required`: the billing owner has no payment method on file and no legacy paid plan. Searches are free; the card keeps the shared archive quota for real accounts."
52480
- '404': { description: Account not found }
52666
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
52667
+
52481
52668
  '501': { description: Only supported on Meta and LinkedIn accounts }
52482
52669
  '503': { description: "Meta's Ad Library is unavailable on Zernio's side (`PLATFORM_DISABLED`); LinkedIn searches are unaffected." }
52483
52670
 
@@ -52519,6 +52706,7 @@ paths:
52519
52706
  own vocabulary, e.g. Meta `REACH`, `LINK_CLICKS`, `OFFSITE_CONVERSIONS`).
52520
52707
  Some platforms vary the estimate by goal; omit to use the platform default.
52521
52708
  responses:
52709
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
52522
52710
  '200':
52523
52711
  description: Normalized reach estimate
52524
52712
  content:
@@ -52538,8 +52726,7 @@ paths:
52538
52726
  '401': { $ref: '#/components/responses/Unauthorized' }
52539
52727
  '403':
52540
52728
  description: Ads access required. Legacy plans need the Ads add-on; included by default on usage-based plans.
52541
- '404': { $ref: '#/components/responses/NotFound' }
52542
-
52729
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
52543
52730
  /v1/ads/targeting/bid-pricing:
52544
52731
  post:
52545
52732
  x-resource-group: "ads"
@@ -52577,6 +52764,7 @@ paths:
52577
52764
  optimizationTargetType: { type: string, description: "LinkedIn optimizationTargetType, e.g. MAX_CLICK, MAX_IMPRESSION." }
52578
52765
  dailyBudget: { type: number, description: "Optional daily budget in whole account-currency units. LinkedIn refines the suggested bid to this budget." }
52579
52766
  responses:
52767
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
52580
52768
  '200':
52581
52769
  description: Pricing insights
52582
52770
  content:
@@ -52610,15 +52798,14 @@ paths:
52610
52798
  '400': { description: "Invalid targeting or unsupported objective/optimization/bid combination." }
52611
52799
  '401': { $ref: '#/components/responses/Unauthorized' }
52612
52800
  '403': { description: "Ads access required." }
52613
- '404': { $ref: '#/components/responses/NotFound' }
52614
-
52801
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
52615
52802
  /v1/ads/targeting/supply-forecast:
52616
52803
  post:
52617
52804
  x-resource-group: "ads"
52618
52805
  operationId: getLinkedInSupplyForecast
52619
52806
  tags: ["Ad Targeting"]
52620
52807
  x-platforms: ["linkedin"]
52621
- summary: Impressions, clicks and spend forecast
52808
+ summary: 'Forecast ad delivery'
52622
52809
  description: |
52623
52810
  LinkedIn-only. Forecasted impressions, clicks, spend and ~20 other
52624
52811
  metrics for a targeting spec over a time range. Wraps LinkedIn's
@@ -52663,6 +52850,7 @@ paths:
52663
52850
  enableAudienceExpansion: { type: boolean, description: "Defaults to false." }
52664
52851
  connectedTelevisionOnly: { type: boolean, description: "Defaults to false." }
52665
52852
  responses:
52853
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
52666
52854
  '200':
52667
52855
  description: Forecast series
52668
52856
  content:
@@ -52694,8 +52882,7 @@ paths:
52694
52882
  '400': { description: "Invalid targeting, missing budget, or LinkedIn forecast validation error (e.g. END_DATE_MAX_HORIZON_FOR_FORECAST)." }
52695
52883
  '401': { $ref: '#/components/responses/Unauthorized' }
52696
52884
  '403': { description: "Ads access required." }
52697
- '404': { $ref: '#/components/responses/NotFound' }
52698
-
52885
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
52699
52886
  /v1/ads/catalogs:
52700
52887
  get:
52701
52888
  x-resource-group: "ads"
@@ -52710,6 +52897,8 @@ paths:
52710
52897
  - { name: accountId, in: query, required: true, schema: { type: string }, description: "A facebook, instagram, or metaads account ID" }
52711
52898
  - { name: adAccountId, in: query, required: true, schema: { type: string }, description: "Meta ad account ID (act_...)" }
52712
52899
  responses:
52900
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
52901
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
52713
52902
  '200':
52714
52903
  description: Catalogs
52715
52904
  content:
@@ -52744,6 +52933,8 @@ paths:
52744
52933
  - { name: catalogId, in: path, required: true, schema: { type: string }, description: "Meta product catalog ID (from GET /v1/ads/catalogs)" }
52745
52934
  - { name: accountId, in: query, required: true, schema: { type: string }, description: "A facebook, instagram, or metaads account ID" }
52746
52935
  responses:
52936
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
52937
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
52747
52938
  '200':
52748
52939
  description: Product sets
52749
52940
  content:
@@ -52779,6 +52970,9 @@ paths:
52779
52970
  - { name: platform, in: query, schema: { type: string, enum: [facebook, instagram, googleads, tiktok, tiktokads, pinterest, linkedin, linkedinads, twitter, xads] } }
52780
52971
  - { name: type, in: query, required: false, schema: { type: string, enum: [customer_list, company_list, engagement, meta_engagement, website, website_retargeting, lookalike, saved_targeting] }, description: "Filter to one audience type. `saved_targeting` returns stored TargetingSpec audiences; the other types return uploaded/derived audiences." }
52781
52972
  responses:
52973
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
52974
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
52975
+ '400': { $ref: '#/components/responses/BadRequest' }
52782
52976
  '200':
52783
52977
  description: Audiences
52784
52978
  content:
@@ -52983,6 +53177,8 @@ paths:
52983
53177
  allOf: [{ $ref: '#/components/schemas/TargetingSpec' }]
52984
53178
  description: "The targeting spec to store."
52985
53179
  responses:
53180
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
53181
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
52986
53182
  '201':
52987
53183
  description: Audience created
52988
53184
  content:
@@ -53244,6 +53440,8 @@ paths:
53244
53440
  - { name: accountId, in: query, required: true, schema: { type: string }, description: "SocialAccount _id (must be a metaads account)." }
53245
53441
  - { name: destinationId, in: query, required: true, schema: { type: string }, description: "Meta pixel/dataset ID." }
53246
53442
  responses:
53443
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
53444
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
53247
53445
  '200':
53248
53446
  description: Match-quality rows, one per event name.
53249
53447
  content:
@@ -53372,6 +53570,7 @@ paths:
53372
53570
  adUserData: { type: string, enum: [GRANTED, DENIED] }
53373
53571
  adPersonalization: { type: string, enum: [GRANTED, DENIED] }
53374
53572
  responses:
53573
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
53375
53574
  '200':
53376
53575
  description: |
53377
53576
  Events processed. Inspect `eventsFailed` and `failures[]` to detect
@@ -53411,8 +53610,8 @@ paths:
53411
53610
  description: |
53412
53611
  Ads access required (Ads add-on on legacy plans, included on usage-based plans),
53413
53612
  OR (for LinkedIn) the connected account lacks the `rw_conversions` scope and must be reconnected.
53414
- '404':
53415
- description: Account not found or not accessible.
53613
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
53614
+
53416
53615
  '422':
53417
53616
  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.'
53418
53617
  '429':
@@ -53512,6 +53711,7 @@ paths:
53512
53711
  type: string
53513
53712
  description: ENHANCEMENT only. The original conversion's user agent (improves match quality).
53514
53713
  responses:
53714
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
53515
53715
  '200':
53516
53716
  description: |
53517
53717
  Adjustments processed. Inspect `adjustmentsFailed` and `failures[]` for
@@ -53538,8 +53738,8 @@ paths:
53538
53738
  '401': { $ref: '#/components/responses/Unauthorized' }
53539
53739
  '403':
53540
53740
  description: Ads access required (Ads add-on on legacy plans, included on usage-based plans).
53541
- '404':
53542
- description: Account not found or not accessible.
53741
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
53742
+
53543
53743
  '405':
53544
53744
  description: Conversion adjustments are only available for Google Ads (the account's platform is not `googleads`).
53545
53745
 
@@ -53549,7 +53749,7 @@ paths:
53549
53749
  operationId: listConversionActions
53550
53750
  tags: [Conversions]
53551
53751
  x-platforms: ["google"]
53552
- summary: List conversion actions and their tag snippets
53752
+ summary: 'List conversion actions'
53553
53753
  description: |
53554
53754
  Lists Google Ads conversion actions on the resolved customer, all types by
53555
53755
  default. Each action's `tagSnippets` (global site tag + event snippet) is
@@ -53571,6 +53771,7 @@ paths:
53571
53771
  - { name: customerId, in: query, required: false, schema: { type: string }, description: "Google Ads customer id (digits only). Resolved automatically when the connection has exactly one accessible customer." }
53572
53772
  - { name: type, in: query, required: false, schema: { type: string }, description: "Filter by Google's ConversionActionType enum (e.g. WEBPAGE, UPLOAD_CLICKS)." }
53573
53773
  responses:
53774
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
53574
53775
  '200':
53575
53776
  description: The resolved customer and its conversion actions.
53576
53777
  content:
@@ -53588,7 +53789,8 @@ paths:
53588
53789
  '401': { $ref: '#/components/responses/Unauthorized' }
53589
53790
  '403':
53590
53791
  description: Ads access required (Ads add-on on legacy plans, included on usage-based plans).
53591
- '404': { $ref: '#/components/responses/NotFound' }
53792
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
53793
+
53592
53794
  '501':
53593
53795
  description: Conversion actions are only available for Google Ads (the account's platform is not `googleads`).
53594
53796
  post:
@@ -53596,7 +53798,7 @@ paths:
53596
53798
  operationId: createConversionAction
53597
53799
  tags: [Conversions]
53598
53800
  x-platforms: ["google"]
53599
- summary: Create a website conversion action
53801
+ summary: 'Create website conversion action'
53600
53802
  description: |
53601
53803
  Creates a `WEBPAGE` conversion action (category `DEFAULT`) and returns it with
53602
53804
  its tag snippets, read back after creation since Google never returns them on
@@ -53635,6 +53837,7 @@ paths:
53635
53837
  type: boolean
53636
53838
  description: "When true, always use defaultValue and ignore any value sent with the event. Defaults to true when defaultValue is set."
53637
53839
  responses:
53840
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
53638
53841
  '201':
53639
53842
  description: The created conversion action, with its tag snippets.
53640
53843
  content:
@@ -53647,7 +53850,8 @@ paths:
53647
53850
  '401': { $ref: '#/components/responses/Unauthorized' }
53648
53851
  '403':
53649
53852
  description: Ads access required (Ads add-on on legacy plans, included on usage-based plans).
53650
- '404': { $ref: '#/components/responses/NotFound' }
53853
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
53854
+
53651
53855
  '501':
53652
53856
  description: Conversion actions are only available for Google Ads (the account's platform is not `googleads`).
53653
53857
 
@@ -53682,6 +53886,7 @@ paths:
53682
53886
  schema: { type: string }
53683
53887
  description: SocialAccount ID (metaads, googleads, linkedinads, tiktokads, or openaiads).
53684
53888
  responses:
53889
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
53685
53890
  '200':
53686
53891
  description: Destinations listed
53687
53892
  content:
@@ -53723,8 +53928,8 @@ paths:
53723
53928
  description: |
53724
53929
  Ads access required (Ads add-on on legacy plans, included on usage-based plans),
53725
53930
  OR (for LinkedIn) the connected account lacks the `rw_conversions` scope and must be reconnected.
53726
- '404':
53727
- description: Account not found or not accessible.
53931
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
53932
+
53728
53933
  '429':
53729
53934
  description: LinkedIn rate limit hit. Retry with backoff.
53730
53935
 
@@ -53886,12 +54091,13 @@ paths:
53886
54091
  description: |
53887
54092
  Ads access required (Ads add-on on legacy plans, included on usage-based plans),
53888
54093
  or the connected LinkedIn account lacks the `rw_conversions` scope (reconnect required).
53889
- '404':
53890
- description: Account not found or not accessible.
54094
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
54095
+
53891
54096
  '405':
53892
54097
  description: Platform does not support destination creation.
53893
54098
  '409':
53894
54099
  description: |
54100
+ The account may also be inactive or need reconnection (code ads_connection_required). Reconnect it and read GET /v1/accounts for its current ID before retrying.
53895
54101
  Google Ads only. A conversion action with the given name already
53896
54102
  exists but has a different category. Use a different name or use
53897
54103
  the existing destination. Error code: `IDEMPOTENCY_CONFLICT`.
@@ -53920,6 +54126,7 @@ paths:
53920
54126
  schema: { type: string }
53921
54127
  description: Numeric ID or full `urn:li:sponsoredAccount:{id}` URN.
53922
54128
  responses:
54129
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
53923
54130
  '200':
53924
54131
  description: Destination fetched
53925
54132
  content:
@@ -53932,7 +54139,8 @@ paths:
53932
54139
  '400': { description: Validation error. }
53933
54140
  '401': { $ref: '#/components/responses/Unauthorized' }
53934
54141
  '403': { description: Ads add-on or LinkedIn reconnect required. }
53935
- '404': { description: Account or destination not found. }
54142
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
54143
+
53936
54144
  '405': { description: Platform does not support fetching a single destination. }
53937
54145
  '429': { description: LinkedIn rate limit hit. Retry with backoff. }
53938
54146
 
@@ -53996,6 +54204,7 @@ paths:
53996
54204
  currencyCode: { type: string, description: ISO 4217. }
53997
54205
  amount: { type: string, description: 'Decimal string (e.g. "49.99").' }
53998
54206
  responses:
54207
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
53999
54208
  '200':
54000
54209
  description: Destination updated (re-fetched canonical state)
54001
54210
  content:
@@ -54008,7 +54217,8 @@ paths:
54008
54217
  '400': { description: Invalid body or LinkedIn validation failure. }
54009
54218
  '401': { $ref: '#/components/responses/Unauthorized' }
54010
54219
  '403': { description: Ads add-on or LinkedIn reconnect required. }
54011
- '404': { description: Account or destination not found. }
54220
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
54221
+
54012
54222
  '405': { description: Platform does not support updating destinations. }
54013
54223
  '429': { description: LinkedIn rate limit hit. Retry with backoff. }
54014
54224
 
@@ -54037,11 +54247,13 @@ paths:
54037
54247
  schema: { type: string }
54038
54248
  description: Required as query OR in JSON body.
54039
54249
  responses:
54250
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
54040
54251
  '204': { description: Soft-deleted. }
54041
54252
  '400': { description: 'adAccountId missing, or accountId is not a valid id.' }
54042
54253
  '401': { $ref: '#/components/responses/Unauthorized' }
54043
54254
  '403': { description: Ads add-on or LinkedIn reconnect required. }
54044
- '404': { description: Account or destination not found. }
54255
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
54256
+
54045
54257
  '405': { description: Platform does not support deleting destinations. }
54046
54258
  '429': { description: LinkedIn rate limit hit. Retry with backoff. }
54047
54259
 
@@ -54067,6 +54279,7 @@ paths:
54067
54279
  required: true
54068
54280
  schema: { type: string }
54069
54281
  responses:
54282
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
54070
54283
  '200':
54071
54284
  description: Associations listed
54072
54285
  content:
@@ -54086,7 +54299,8 @@ paths:
54086
54299
  '400': { description: Validation error. }
54087
54300
  '401': { $ref: '#/components/responses/Unauthorized' }
54088
54301
  '403': { description: Ads add-on or LinkedIn reconnect required. }
54089
- '404': { description: Account or destination not found. }
54302
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
54303
+
54090
54304
  '405': { description: Platform does not support associations. }
54091
54305
  '429': { description: LinkedIn rate limit hit. Retry with backoff. }
54092
54306
 
@@ -54122,6 +54336,7 @@ paths:
54122
54336
  type: string
54123
54337
  description: Numeric campaign ID or full `urn:li:sponsoredCampaign:{id}` URN.
54124
54338
  responses:
54339
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
54125
54340
  '200':
54126
54341
  description: |
54127
54342
  Per-campaign batch result. Status is 200 even when some rows
@@ -54148,7 +54363,8 @@ paths:
54148
54363
  '400': { description: Invalid body. }
54149
54364
  '401': { $ref: '#/components/responses/Unauthorized' }
54150
54365
  '403': { description: Ads add-on or LinkedIn reconnect required. }
54151
- '404': { description: Account or destination not found. }
54366
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
54367
+
54152
54368
  '405': { description: Platform does not support associations. }
54153
54369
  '429': { description: LinkedIn rate limit hit. Retry with backoff. }
54154
54370
 
@@ -54174,6 +54390,7 @@ paths:
54174
54390
  - { name: adAccountId, in: query, required: true, schema: { type: string } }
54175
54391
  - { name: campaignIds, in: query, required: true, schema: { type: string }, description: 'Comma-separated list of campaign IDs.' }
54176
54392
  responses:
54393
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
54177
54394
  '200':
54178
54395
  description: |
54179
54396
  Per-campaign batch result. Status is 200 even when some rows
@@ -54202,7 +54419,8 @@ paths:
54202
54419
  a valid id.
54203
54420
  '401': { $ref: '#/components/responses/Unauthorized' }
54204
54421
  '403': { description: Ads add-on or LinkedIn reconnect required. }
54205
- '404': { description: Account or destination not found. }
54422
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
54423
+
54206
54424
  '405': { description: Platform does not support associations. }
54207
54425
  '429': { description: LinkedIn rate limit hit. Retry with backoff. }
54208
54426
 
@@ -54242,6 +54460,7 @@ paths:
54242
54460
  enum: [ALL, DAILY, MONTHLY, YEARLY]
54243
54461
  default: DAILY
54244
54462
  responses:
54463
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
54245
54464
  '200':
54246
54465
  description: Metrics rows
54247
54466
  content:
@@ -54264,7 +54483,8 @@ paths:
54264
54483
  '400': { description: Validation error or invalid date range. }
54265
54484
  '401': { $ref: '#/components/responses/Unauthorized' }
54266
54485
  '403': { description: Ads add-on or LinkedIn reconnect required. }
54267
- '404': { description: Account or destination not found. }
54486
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
54487
+
54268
54488
  '405': { description: Platform does not support metrics readback. }
54269
54489
  '429': { description: LinkedIn analytics rate limit hit. }
54270
54490
 
@@ -54555,6 +54775,7 @@ paths:
54555
54775
  budgetType: daily
54556
54776
  status: PAUSED
54557
54777
  responses:
54778
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
54558
54779
  '201':
54559
54780
  description: |
54560
54781
  Ad(s) created and submitted for review. The route shares its handler with
@@ -54576,7 +54797,8 @@ paths:
54576
54797
  '401': { $ref: '#/components/responses/Unauthorized' }
54577
54798
  '403':
54578
54799
  description: 'Returned with code `ads_allowance_exceeded` when the team has no payment method on file and has reached the 500 free live ads: add a card to resume.'
54579
- '404': { description: Account not found }
54800
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
54801
+
54580
54802
  '422': { description: "No Facebook Page resolved for the account" }
54581
54803
  '502': { description: "Meta accepted the request then failed to produce the media (upload session, chunk transfer, processing timeout, or a response with no image hash). Inspect `platformError.reason`." }
54582
54804
 
@@ -54612,6 +54834,7 @@ paths:
54612
54834
  format: uri
54613
54835
  description: "Website shown as the creative's link. Required: Meta rejects tel: as link_data.link; the phone number rides only the CTA."
54614
54836
  responses:
54837
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
54615
54838
  '201':
54616
54839
  description: |
54617
54840
  Ad(s) created and submitted for review. The route shares its handler with
@@ -54633,7 +54856,8 @@ paths:
54633
54856
  '401': { $ref: '#/components/responses/Unauthorized' }
54634
54857
  '403':
54635
54858
  description: 'Returned with code `ads_allowance_exceeded` when the team has no payment method on file and has reached the 500 free live ads: add a card to resume.'
54636
- '404': { description: Account not found }
54859
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
54860
+
54637
54861
  '422': { description: "No Facebook Page resolved for the account" }
54638
54862
  '502': { description: "Meta accepted the request then failed to produce the media (upload session, chunk transfer, processing timeout, or a response with no image hash). Inspect `platformError.reason`." }
54639
54863
 
@@ -54681,6 +54905,7 @@ paths:
54681
54905
  budgetType: daily
54682
54906
  status: PAUSED
54683
54907
  responses:
54908
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
54684
54909
  '201':
54685
54910
  description: |
54686
54911
  CTWA ad(s) created and submitted to Meta for review. Response is a
@@ -54710,7 +54935,8 @@ paths:
54710
54935
  '401': { $ref: '#/components/responses/Unauthorized' }
54711
54936
  '403':
54712
54937
  description: 'Forbidden. Also returned with code `ads_allowance_exceeded` when the team has no payment method on file and has reached the 500 free live ads: add a card to resume.'
54713
- '404': { description: SocialAccount not found. }
54938
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
54939
+
54714
54940
  '422':
54715
54941
  description: Page is not connected to a verified WhatsApp number.
54716
54942
  '502':
@@ -54732,6 +54958,8 @@ paths:
54732
54958
  - { name: accountId, in: path, required: true, schema: { type: string }, description: "Meta ads SocialAccount id." }
54733
54959
  - { name: adAccountId, in: query, required: true, schema: { type: string }, description: "Meta ad account id (act_<n>)." }
54734
54960
  responses:
54961
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
54962
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
54735
54963
  '200':
54736
54964
  description: Custom conversions
54737
54965
  content:
@@ -54751,7 +54979,7 @@ paths:
54751
54979
  operationId: createCustomConversion
54752
54980
  tags: ["Ad Accounts"]
54753
54981
  x-platforms: ["meta"]
54754
- summary: Create or reuse a custom conversion
54982
+ summary: 'Create custom conversion'
54755
54983
  description: |-
54756
54984
  Provision the Meta custom conversion an ads flow optimises toward, and hand back the
54757
54985
  `customConversionId` for `promotedObject.customConversionId` on POST /v1/ads/create.
@@ -54783,6 +55011,8 @@ paths:
54783
55011
  customEventType: { type: string, description: "Meta custom_event_type, e.g. LEAD, PURCHASE, OTHER." }
54784
55012
  rule: { type: object, description: "Meta conversion rule, forwarded verbatim." }
54785
55013
  responses:
55014
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
55015
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
54786
55016
  '200':
54787
55017
  description: An existing custom conversion was reused
54788
55018
  content:
@@ -56201,6 +56431,7 @@ paths:
56201
56431
  - { name: accountId, in: path, required: true, schema: { type: string }, description: 'Ads SocialAccount id (platform `metaads` or `openaiads`).' }
56202
56432
  - { 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.' }
56203
56433
  responses:
56434
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
56204
56435
  '200':
56205
56436
  description: Tracking tags listed
56206
56437
  content:
@@ -56215,7 +56446,8 @@ paths:
56215
56446
  '400': { description: 'Account platform not supported, or invalid `adAccountId`.' }
56216
56447
  '401': { $ref: '#/components/responses/Unauthorized' }
56217
56448
  '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).' }
56218
- '404': { description: Account not found or not accessible. }
56449
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
56450
+
56219
56451
  '405': { description: Platform does not support listing tracking tags. }
56220
56452
  '502': { description: 'Meta was unreachable or returned an unclassified error (type: platform_error; the raw Meta payload is in platformError). Retryable.' }
56221
56453
 
@@ -56273,6 +56505,7 @@ paths:
56273
56505
  enum: [order_created, lead_created, items_added, contents_viewed, checkout_started, registration_completed, subscription_created, trial_started, appointment_scheduled, page_viewed, app_installed, app_opened]
56274
56506
  description: 'OpenAI Ads only (ignored by Meta). When set, also provisions a standard conversion event setting wired to the new pixel, so `goal: conversions` ad creates on `POST /v1/ads/create` have an event to reference immediately.'
56275
56507
  responses:
56508
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
56276
56509
  '201':
56277
56510
  description: Tracking tag created
56278
56511
  content:
@@ -56285,7 +56518,8 @@ paths:
56285
56518
  '400': { description: 'Invalid body, invalid `adAccountId`, over the per-business pixel cap, or ad account not in a Business Manager.' }
56286
56519
  '401': { $ref: '#/components/responses/Unauthorized' }
56287
56520
  '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).' }
56288
- '404': { description: Account not found or not accessible. }
56521
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
56522
+
56289
56523
  '405': { description: Platform does not support creating tracking tags. }
56290
56524
  '422': { description: 'OpenAI Ads only: the ad account is not enabled for pixel management. Contact your OpenAI partner representative.' }
56291
56525
  '502': { description: 'Meta was unreachable or returned an unclassified error (type: platform_error; the raw Meta payload is in platformError). Creating a pixel is NOT idempotent, so before retrying confirm with GET /v1/accounts/{accountId}/tracking-tags that no pixel was created.' }
@@ -56309,6 +56543,8 @@ paths:
56309
56543
  - { name: accountId, in: path, required: true, schema: { type: string } }
56310
56544
  - { name: tagId, in: path, required: true, schema: { type: string }, description: 'Pixel id.' }
56311
56545
  responses:
56546
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
56547
+ '400': { $ref: '#/components/responses/BadRequest' }
56312
56548
  '200':
56313
56549
  description: Tracking tag fetched
56314
56550
  content:
@@ -56320,7 +56556,8 @@ paths:
56320
56556
  tag: { $ref: '#/components/schemas/TrackingTag' }
56321
56557
  '401': { $ref: '#/components/responses/Unauthorized' }
56322
56558
  '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).' }
56323
- '404': { description: Account or tracking tag not found. }
56559
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
56560
+
56324
56561
  '405': { description: Platform does not support fetching a tracking tag. }
56325
56562
  '502': { description: 'Meta was unreachable or returned an unclassified error (type: platform_error; the raw Meta payload is in platformError). Retryable.' }
56326
56563
 
@@ -56375,6 +56612,7 @@ paths:
56375
56612
  type: string
56376
56613
  enum: [advertising_and_analytics, analytics_only, empty]
56377
56614
  responses:
56615
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
56378
56616
  '200':
56379
56617
  description: Tracking tag updated (re-fetched canonical state)
56380
56618
  content:
@@ -56387,7 +56625,8 @@ paths:
56387
56625
  '400': { description: Invalid body (e.g. no fields supplied) or Meta validation failure. }
56388
56626
  '401': { $ref: '#/components/responses/Unauthorized' }
56389
56627
  '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).' }
56390
- '404': { description: Account or tracking tag not found. }
56628
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
56629
+
56391
56630
  '405': { description: Platform does not support updating tracking tags. }
56392
56631
  '502': { description: 'Meta was unreachable or returned an unclassified error (type: platform_error; the raw Meta payload is in platformError). Retryable.' }
56393
56632
 
@@ -56405,6 +56644,8 @@ paths:
56405
56644
  - { name: accountId, in: path, required: true, schema: { type: string } }
56406
56645
  - { name: tagId, in: path, required: true, schema: { type: string }, description: 'Pixel id.' }
56407
56646
  responses:
56647
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
56648
+ '400': { $ref: '#/components/responses/BadRequest' }
56408
56649
  '200':
56409
56650
  description: Shared ad accounts listed
56410
56651
  content:
@@ -56418,7 +56659,8 @@ paths:
56418
56659
  items: { $ref: '#/components/schemas/SharedAdAccount' }
56419
56660
  '401': { $ref: '#/components/responses/Unauthorized' }
56420
56661
  '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).' }
56421
- '404': { description: Account or tracking tag not found. }
56662
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
56663
+
56422
56664
  '405': { description: Platform does not support shared accounts. }
56423
56665
  '502': { description: 'Meta was unreachable or returned an unclassified error (type: platform_error; the raw Meta payload is in platformError). Retryable.' }
56424
56666
 
@@ -56449,6 +56691,7 @@ paths:
56449
56691
  properties:
56450
56692
  adAccountId: { type: string, description: 'Ad account to share with, e.g. `act_123456789`.' }
56451
56693
  responses:
56694
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
56452
56695
  '201':
56453
56696
  description: Tracking tag shared with the ad account
56454
56697
  content:
@@ -56461,7 +56704,8 @@ paths:
56461
56704
  '400': { description: 'Invalid body / `adAccountId`, or Meta rejected the share (e.g. personal ad account).' }
56462
56705
  '401': { $ref: '#/components/responses/Unauthorized' }
56463
56706
  '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).' }
56464
- '404': { description: Account or tracking tag not found. }
56707
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
56708
+
56465
56709
  '405': { description: Platform does not support shared accounts. }
56466
56710
  '502': { description: 'Meta was unreachable or returned an unclassified error (type: platform_error; the raw Meta payload is in platformError). Retryable.' }
56467
56711
 
@@ -56482,11 +56726,13 @@ paths:
56482
56726
  - { name: tagId, in: path, required: true, schema: { type: string }, description: 'Pixel id.' }
56483
56727
  - { name: adAccountId, in: query, required: false, schema: { type: string }, description: 'Ad account to unshare, e.g. `act_123456789`. May also be sent in the JSON body.' }
56484
56728
  responses:
56729
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
56485
56730
  '204': { description: Ad account unshared (no content). }
56486
56731
  '400': { description: '`adAccountId` missing (neither query nor body), or Meta rejected the unshare.' }
56487
56732
  '401': { $ref: '#/components/responses/Unauthorized' }
56488
56733
  '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).' }
56489
- '404': { description: Account or tracking tag not found. }
56734
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
56735
+
56490
56736
  '405': { description: Platform does not support shared accounts. }
56491
56737
  '502': { description: 'Meta was unreachable or returned an unclassified error (type: platform_error; the raw Meta payload is in platformError). Retryable.' }
56492
56738
 
@@ -56534,6 +56780,7 @@ paths:
56534
56780
  - { name: startTime, in: query, required: false, schema: { type: integer }, description: 'Unix seconds lower bound.' }
56535
56781
  - { name: endTime, in: query, required: false, schema: { type: integer }, description: 'Unix seconds upper bound.' }
56536
56782
  responses:
56783
+ '409': { $ref: '#/components/responses/AccountConnectionRequired' }
56537
56784
  '200':
56538
56785
  description: Stats fetched
56539
56786
  content:
@@ -56554,7 +56801,8 @@ paths:
56554
56801
  '400': { description: Invalid query parameter. }
56555
56802
  '401': { $ref: '#/components/responses/Unauthorized' }
56556
56803
  '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).' }
56557
- '404': { description: Account or tracking tag not found. }
56804
+ '404': { $ref: '#/components/responses/AccountUnavailable' }
56805
+
56558
56806
  '405': { description: Platform does not support tracking-tag stats. }
56559
56807
  '502': { description: 'Meta was unreachable or returned an unclassified error (type: platform_error; the raw Meta payload is in platformError). Retryable.' }
56560
56808
 
@@ -57122,3 +57370,259 @@ paths:
57122
57370
  '400': { $ref: '#/components/responses/BadRequest' }
57123
57371
  '401': { $ref: '#/components/responses/Unauthorized' }
57124
57372
  '404': { description: Verification not found (or already reaped). }
57373
+
57374
+ /v1/ads/pixels:
57375
+ get:
57376
+ operationId: 'listTikTokAdPixels'
57377
+ summary: 'List TikTok ad pixels'
57378
+ description: 'Lists pixels and their supported optimization events for a connected TikTok Ads account. The advertiser defaults to the first advertiser on the connection. Reconnect if Pixel Management permission has not been granted.'
57379
+ tags:
57380
+ - 'Ad Accounts'
57381
+ x-resource-group: 'ads'
57382
+ x-platforms:
57383
+ - 'tiktok'
57384
+ security:
57385
+ - bearerAuth: []
57386
+ parameters:
57387
+ - &a1
57388
+ name: 'accountId'
57389
+ in: 'query'
57390
+ required: true
57391
+ schema: &a7
57392
+ type: 'string'
57393
+ pattern: '^[a-fA-F0-9]{24}$'
57394
+ description: 'Zernio SocialAccount ID.'
57395
+ - name: 'advertiserId'
57396
+ in: 'query'
57397
+ schema:
57398
+ type: 'string'
57399
+ description: 'Advertiser belonging to this connection.'
57400
+ - name: 'code'
57401
+ in: 'query'
57402
+ schema:
57403
+ type: 'string'
57404
+ description: 'Filter by a Pixel Code.'
57405
+ responses:
57406
+ "200":
57407
+ description: 'TikTok pixels.'
57408
+ content:
57409
+ application/json:
57410
+ schema:
57411
+ type: 'object'
57412
+ properties:
57413
+ advertiserId:
57414
+ type: 'string'
57415
+ pixels:
57416
+ type: 'array'
57417
+ items:
57418
+ type: 'object'
57419
+ properties:
57420
+ pixelId:
57421
+ type: 'string'
57422
+ pixelCode:
57423
+ type: 'string'
57424
+ name:
57425
+ type: 'string'
57426
+ events:
57427
+ type: 'array'
57428
+ items:
57429
+ type: 'string'
57430
+ eventDetails:
57431
+ type: 'array'
57432
+ items:
57433
+ type: 'object'
57434
+ properties:
57435
+ name:
57436
+ type: 'string'
57437
+ optimizationEvent:
57438
+ type:
57439
+ - 'string'
57440
+ - 'null'
57441
+ custom:
57442
+ type: 'boolean'
57443
+ example:
57444
+ advertiserId: '7330955083452284929'
57445
+ pixels: []
57446
+ "400": &a2
57447
+ $ref: '#/components/responses/BadRequest'
57448
+ "401": &a3
57449
+ $ref: '#/components/responses/Unauthorized'
57450
+ "403":
57451
+ description: 'Ads access required.'
57452
+ "404": &a4
57453
+ $ref: '#/components/responses/AccountUnavailable'
57454
+ "409": &a5
57455
+ $ref: '#/components/responses/AccountConnectionRequired'
57456
+ "422":
57457
+ description: 'Pixel Management permission is missing (code reconnect_required). Reconnect TikTok Ads to grant it.'
57458
+ /v1/ads/partnership-content:
57459
+ get:
57460
+ operationId: 'listPartnershipAdContent'
57461
+ summary: 'List partnership ad content'
57462
+ description: 'Private beta. Lists creator Instagram posts available to the advertiser for Partnership Ads. Supply creatorUsername or postUrl. Requires instagram_branded_content_ads_brand permission and an advertiser Instagram Business Account.'
57463
+ tags:
57464
+ - 'Ad Creatives'
57465
+ x-resource-group: 'ads'
57466
+ x-platforms:
57467
+ - 'meta'
57468
+ security:
57469
+ - bearerAuth: []
57470
+ parameters:
57471
+ - *a1
57472
+ - name: 'creatorUsername'
57473
+ in: 'query'
57474
+ schema:
57475
+ type: 'string'
57476
+ description: 'Creator username. Required unless postUrl is supplied.'
57477
+ - name: 'postUrl'
57478
+ in: 'query'
57479
+ schema:
57480
+ type: 'string'
57481
+ format: 'uri'
57482
+ description: 'Instagram post permalink. Required unless creatorUsername is supplied.'
57483
+ - name: 'onlyAllowlisted'
57484
+ in: 'query'
57485
+ schema:
57486
+ type: 'boolean'
57487
+ description: 'Return only creators with account-level permission.'
57488
+ responses:
57489
+ "200":
57490
+ description: 'Advertisable Instagram media.'
57491
+ content:
57492
+ application/json:
57493
+ schema:
57494
+ type: 'object'
57495
+ properties:
57496
+ media:
57497
+ type: 'array'
57498
+ items:
57499
+ type: 'object'
57500
+ properties:
57501
+ id:
57502
+ type: 'string'
57503
+ permalink:
57504
+ type: 'string'
57505
+ ownerId:
57506
+ type: 'string'
57507
+ hasPermissionForPartnershipAd:
57508
+ type: 'boolean'
57509
+ isCreatorAllowlisted:
57510
+ type: 'boolean'
57511
+ eligibilityErrors:
57512
+ type: 'array'
57513
+ items:
57514
+ type: 'string'
57515
+ recommendedCampaignObjectives:
57516
+ type: 'array'
57517
+ items:
57518
+ type: 'string'
57519
+ example:
57520
+ media: []
57521
+ "400": *a2
57522
+ "401": *a3
57523
+ "403": &a6
57524
+ description: 'Ads access required. Partnership operations also require private beta access.'
57525
+ "404": *a4
57526
+ "409": *a5
57527
+ "422":
57528
+ description: 'The advertiser Instagram Business Account could not be resolved.'
57529
+ /v1/ads/partnership-permissions:
57530
+ get:
57531
+ operationId: 'listPartnershipAdPermissions'
57532
+ summary: 'List partnership permissions'
57533
+ description: 'Private beta. Lists granted or pending creator permissions for the advertiser Instagram Business Account. Requires instagram_branded_content_ads_brand permission.'
57534
+ tags:
57535
+ - 'Ad Creatives'
57536
+ x-resource-group: 'ads'
57537
+ x-platforms:
57538
+ - 'meta'
57539
+ security:
57540
+ - bearerAuth: []
57541
+ parameters:
57542
+ - *a1
57543
+ - name: 'creatorUsername'
57544
+ in: 'query'
57545
+ schema:
57546
+ type: 'string'
57547
+ description: 'Filter by creator username.'
57548
+ responses:
57549
+ "200":
57550
+ description: 'Partnership permissions.'
57551
+ content:
57552
+ application/json:
57553
+ schema:
57554
+ type: 'object'
57555
+ properties:
57556
+ permissions:
57557
+ type: 'array'
57558
+ items: &a8
57559
+ type: 'object'
57560
+ properties:
57561
+ id:
57562
+ type: 'string'
57563
+ permissionType:
57564
+ type: 'string'
57565
+ status:
57566
+ type: 'string'
57567
+ example:
57568
+ permissions: []
57569
+ "400": *a2
57570
+ "401": *a3
57571
+ "403": *a6
57572
+ "404": *a4
57573
+ "409": *a5
57574
+ "422":
57575
+ description: 'The advertiser Instagram Business Account could not be resolved.'
57576
+ post:
57577
+ operationId: 'setPartnershipAdPermission'
57578
+ summary: 'Set partnership permission'
57579
+ description: 'Private beta. Requests permission from a creator or revokes it when revoke is true. Requests require the creator to approve in Instagram. Requires instagram_branded_content_ads_brand permission.'
57580
+ tags:
57581
+ - 'Ad Creatives'
57582
+ x-resource-group: 'ads'
57583
+ x-platforms:
57584
+ - 'meta'
57585
+ security:
57586
+ - bearerAuth: []
57587
+ requestBody:
57588
+ required: true
57589
+ content:
57590
+ application/json:
57591
+ schema:
57592
+ type: 'object'
57593
+ required:
57594
+ - 'accountId'
57595
+ - 'creatorUsername'
57596
+ properties:
57597
+ accountId: *a7
57598
+ creatorUsername:
57599
+ type: 'string'
57600
+ minLength: 1
57601
+ revoke:
57602
+ type: 'boolean'
57603
+ example:
57604
+ accountId: '507f1f77bcf86cd799439011'
57605
+ creatorUsername: 'example_creator'
57606
+ revoke: false
57607
+ responses:
57608
+ "200": &a9
57609
+ description: 'Partnership permission state.'
57610
+ content:
57611
+ application/json:
57612
+ schema:
57613
+ type: 'object'
57614
+ properties:
57615
+ permission: *a8
57616
+ example:
57617
+ permission:
57618
+ id: '123456789'
57619
+ permissionType: 'AD'
57620
+ status: 'PENDING'
57621
+ "201": *a9
57622
+ "400": *a2
57623
+ "401": *a3
57624
+ "403": *a6
57625
+ "404": *a4
57626
+ "409": *a5
57627
+ "422":
57628
+ description: 'The advertiser Instagram Business Account could not be resolved.'