late-sdk 0.0.97 → 0.0.99

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 (128) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +53 -0
  3. data/docs/Ad.md +58 -0
  4. data/docs/AdAudiencesApi.md +365 -0
  5. data/docs/AdBudget.md +20 -0
  6. data/docs/AdCampaign.md +40 -0
  7. data/docs/AdCampaignsApi.md +165 -0
  8. data/docs/AdMetrics.md +34 -0
  9. data/docs/AdSchedule.md +20 -0
  10. data/docs/AddUsersToAdAudience200Response.md +22 -0
  11. data/docs/AddUsersToAdAudienceRequest.md +18 -0
  12. data/docs/AddUsersToAdAudienceRequestUsersInner.md +20 -0
  13. data/docs/AdsApi.md +726 -0
  14. data/docs/BoostPostRequest.md +36 -0
  15. data/docs/BoostPostRequestBudget.md +20 -0
  16. data/docs/BoostPostRequestSchedule.md +20 -0
  17. data/docs/BoostPostRequestTargeting.md +24 -0
  18. data/docs/CreateAdAudience201Response.md +20 -0
  19. data/docs/CreateAdAudienceRequest.md +36 -0
  20. data/docs/CreateStandaloneAdRequest.md +56 -0
  21. data/docs/GetAd200Response.md +18 -0
  22. data/docs/GetAdAnalytics200Response.md +20 -0
  23. data/docs/GetAdAnalytics200ResponseAd.md +24 -0
  24. data/docs/GetAdAnalytics200ResponseAnalytics.md +22 -0
  25. data/docs/GetAdAnalytics200ResponseAnalyticsDailyInner.md +36 -0
  26. data/docs/GetAdAudience200Response.md +20 -0
  27. data/docs/ListAdAccounts200Response.md +18 -0
  28. data/docs/ListAdAccounts200ResponseAccountsInner.md +24 -0
  29. data/docs/ListAdAudiences200Response.md +18 -0
  30. data/docs/ListAdAudiences200ResponseAudiencesInner.md +32 -0
  31. data/docs/ListAdCampaigns200Response.md +20 -0
  32. data/docs/ListAds200Response.md +20 -0
  33. data/docs/SearchAdInterests200Response.md +18 -0
  34. data/docs/SearchAdInterests200ResponseInterestsInner.md +22 -0
  35. data/docs/SyncExternalAds200Response.md +24 -0
  36. data/docs/UpdateAd200Response.md +20 -0
  37. data/docs/UpdateAdCampaignStatus200Response.md +22 -0
  38. data/docs/UpdateAdCampaignStatusRequest.md +20 -0
  39. data/docs/UpdateAdRequest.md +24 -0
  40. data/docs/UpdateAdRequestBudget.md +20 -0
  41. data/docs/UpdateAdRequestTargeting.md +24 -0
  42. data/docs/UpdatePostMetadataRequest.md +7 -1
  43. data/lib/late-sdk/api/ad_audiences_api.rb +368 -0
  44. data/lib/late-sdk/api/ad_campaigns_api.rb +201 -0
  45. data/lib/late-sdk/api/ads_api.rb +719 -0
  46. data/lib/late-sdk/models/ad.rb +399 -0
  47. data/lib/late-sdk/models/ad_budget.rb +190 -0
  48. data/lib/late-sdk/models/ad_campaign.rb +293 -0
  49. data/lib/late-sdk/models/ad_metrics.rb +222 -0
  50. data/lib/late-sdk/models/ad_schedule.rb +156 -0
  51. data/lib/late-sdk/models/add_users_to_ad_audience200_response.rb +165 -0
  52. data/lib/late-sdk/models/add_users_to_ad_audience_request.rb +175 -0
  53. data/lib/late-sdk/models/add_users_to_ad_audience_request_users_inner.rb +157 -0
  54. data/lib/late-sdk/models/boost_post_request.rb +350 -0
  55. data/lib/late-sdk/models/boost_post_request_budget.rb +215 -0
  56. data/lib/late-sdk/models/boost_post_request_schedule.rb +157 -0
  57. data/lib/late-sdk/models/boost_post_request_targeting.rb +234 -0
  58. data/lib/late-sdk/models/create_ad_audience201_response.rb +156 -0
  59. data/lib/late-sdk/models/create_ad_audience_request.rb +391 -0
  60. data/lib/late-sdk/models/create_standalone_ad_request.rb +585 -0
  61. data/lib/late-sdk/models/get_ad200_response.rb +147 -0
  62. data/lib/late-sdk/models/get_ad_analytics200_response.rb +156 -0
  63. data/lib/late-sdk/models/get_ad_analytics200_response_ad.rb +174 -0
  64. data/lib/late-sdk/models/get_ad_analytics200_response_analytics.rb +169 -0
  65. data/lib/late-sdk/models/get_ad_analytics200_response_analytics_daily_inner.rb +238 -0
  66. data/lib/late-sdk/models/get_ad_audience200_response.rb +157 -0
  67. data/lib/late-sdk/models/list_ad_accounts200_response.rb +149 -0
  68. data/lib/late-sdk/models/list_ad_accounts200_response_accounts_inner.rb +175 -0
  69. data/lib/late-sdk/models/list_ad_audiences200_response.rb +149 -0
  70. data/lib/late-sdk/models/list_ad_audiences200_response_audiences_inner.rb +244 -0
  71. data/lib/late-sdk/models/list_ad_campaigns200_response.rb +158 -0
  72. data/lib/late-sdk/models/list_ads200_response.rb +158 -0
  73. data/lib/late-sdk/models/search_ad_interests200_response.rb +149 -0
  74. data/lib/late-sdk/models/search_ad_interests200_response_interests_inner.rb +165 -0
  75. data/lib/late-sdk/models/sync_external_ads200_response.rb +177 -0
  76. data/lib/late-sdk/models/update_ad200_response.rb +156 -0
  77. data/lib/late-sdk/models/update_ad_campaign_status200_response.rb +169 -0
  78. data/lib/late-sdk/models/update_ad_campaign_status_request.rb +216 -0
  79. data/lib/late-sdk/models/update_ad_request.rb +208 -0
  80. data/lib/late-sdk/models/update_ad_request_budget.rb +191 -0
  81. data/lib/late-sdk/models/update_ad_request_targeting.rb +235 -0
  82. data/lib/late-sdk/models/update_post_metadata_request.rb +34 -4
  83. data/lib/late-sdk/version.rb +1 -1
  84. data/lib/late-sdk.rb +39 -0
  85. data/openapi.yaml +693 -0
  86. data/spec/api/ad_audiences_api_spec.rb +98 -0
  87. data/spec/api/ad_campaigns_api_spec.rb +67 -0
  88. data/spec/api/ads_api_spec.rb +163 -0
  89. data/spec/models/ad_budget_spec.rb +46 -0
  90. data/spec/models/ad_campaign_spec.rb +110 -0
  91. data/spec/models/ad_metrics_spec.rb +84 -0
  92. data/spec/models/ad_schedule_spec.rb +42 -0
  93. data/spec/models/ad_spec.rb +172 -0
  94. data/spec/models/add_users_to_ad_audience200_response_spec.rb +48 -0
  95. data/spec/models/add_users_to_ad_audience_request_spec.rb +36 -0
  96. data/spec/models/add_users_to_ad_audience_request_users_inner_spec.rb +42 -0
  97. data/spec/models/boost_post_request_budget_spec.rb +46 -0
  98. data/spec/models/boost_post_request_schedule_spec.rb +42 -0
  99. data/spec/models/boost_post_request_spec.rb +94 -0
  100. data/spec/models/boost_post_request_targeting_spec.rb +54 -0
  101. data/spec/models/create_ad_audience201_response_spec.rb +42 -0
  102. data/spec/models/create_ad_audience_request_spec.rb +94 -0
  103. data/spec/models/create_standalone_ad_request_spec.rb +166 -0
  104. data/spec/models/get_ad200_response_spec.rb +36 -0
  105. data/spec/models/get_ad_analytics200_response_ad_spec.rb +54 -0
  106. data/spec/models/get_ad_analytics200_response_analytics_daily_inner_spec.rb +90 -0
  107. data/spec/models/get_ad_analytics200_response_analytics_spec.rb +48 -0
  108. data/spec/models/get_ad_analytics200_response_spec.rb +42 -0
  109. data/spec/models/get_ad_audience200_response_spec.rb +42 -0
  110. data/spec/models/list_ad_accounts200_response_accounts_inner_spec.rb +54 -0
  111. data/spec/models/list_ad_accounts200_response_spec.rb +36 -0
  112. data/spec/models/list_ad_audiences200_response_audiences_inner_spec.rb +82 -0
  113. data/spec/models/list_ad_audiences200_response_spec.rb +36 -0
  114. data/spec/models/list_ad_campaigns200_response_spec.rb +42 -0
  115. data/spec/models/list_ads200_response_spec.rb +42 -0
  116. data/spec/models/search_ad_interests200_response_interests_inner_spec.rb +48 -0
  117. data/spec/models/search_ad_interests200_response_spec.rb +36 -0
  118. data/spec/models/sync_external_ads200_response_spec.rb +54 -0
  119. data/spec/models/update_ad200_response_spec.rb +42 -0
  120. data/spec/models/update_ad_campaign_status200_response_spec.rb +48 -0
  121. data/spec/models/update_ad_campaign_status_request_spec.rb +50 -0
  122. data/spec/models/update_ad_request_budget_spec.rb +46 -0
  123. data/spec/models/update_ad_request_spec.rb +58 -0
  124. data/spec/models/update_ad_request_targeting_spec.rb +54 -0
  125. data/spec/models/update_post_metadata_request_spec.rb +18 -0
  126. data/zernio-sdk-0.0.99.gem +0 -0
  127. metadata +159 -3
  128. data/zernio-sdk-0.0.97.gem +0 -0
data/openapi.yaml CHANGED
@@ -233,6 +233,22 @@ tags:
233
233
  Comment-to-DM growth automations. Set up keyword triggers on Instagram/Facebook posts so
234
234
  commenters automatically receive a DM. Supports dedup, optional public comment reply, and
235
235
  auto-creates contacts.
236
+ - name: Ads
237
+ description: |
238
+ Paid advertising management across Meta (Facebook/Instagram), Google, TikTok, LinkedIn, Pinterest, and X/Twitter.
239
+ Create, boost, pause/resume ads and campaigns, view metrics, manage audiences, and sync external ads.
240
+ Requires the Ads add-on.
241
+ - name: Ad Campaigns
242
+ description: |
243
+ Campaign-level operations. Campaigns are virtual aggregations of ads grouped by their platform campaign ID.
244
+ List campaigns with aggregate metrics, or pause/resume all ads in a campaign at once.
245
+ Requires the Ads add-on.
246
+ - name: Ad Audiences
247
+ description: |
248
+ Custom audience management for ad targeting. Create customer lists, website retargeting audiences,
249
+ and lookalike audiences. Upload user data (hashed server-side). Currently Meta-only for creation,
250
+ read-only for other platforms.
251
+ Requires the Ads add-on.
236
252
  - name: Webhooks
237
253
  description: |
238
254
  Configure webhooks for real-time notifications. Events: post.scheduled, post.published, post.failed, post.partial, post.cancelled, post.recycled, account.connected, account.disconnected, message.received, comment.received, webhook.test.
@@ -2615,6 +2631,75 @@ components:
2615
2631
  properties:
2616
2632
  user:
2617
2633
  $ref: '#/components/schemas/User'
2634
+ AdMetrics:
2635
+ type: object
2636
+ properties:
2637
+ spend: { type: number }
2638
+ impressions: { type: integer }
2639
+ reach: { type: integer }
2640
+ clicks: { type: integer }
2641
+ ctr: { type: number, description: Click-through rate (%) }
2642
+ cpc: { type: number, description: Cost per click }
2643
+ cpm: { type: number, description: Cost per 1000 impressions }
2644
+ engagement: { type: integer }
2645
+ lastSyncedAt: { type: string, format: date-time }
2646
+ Ad:
2647
+ type: object
2648
+ properties:
2649
+ _id: { type: string }
2650
+ name: { type: string }
2651
+ platform: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter] }
2652
+ status: { type: string, enum: [active, paused, pending_review, rejected, completed, cancelled, error] }
2653
+ adType: { type: string, enum: [boost, standalone] }
2654
+ goal: { type: string, enum: [engagement, traffic, awareness, video_views] }
2655
+ isExternal: { type: boolean, description: True for ads synced from platform ad managers }
2656
+ budget:
2657
+ type: object
2658
+ nullable: true
2659
+ properties:
2660
+ amount: { type: number }
2661
+ type: { type: string, enum: [daily, lifetime] }
2662
+ metrics:
2663
+ allOf:
2664
+ - { $ref: '#/components/schemas/AdMetrics' }
2665
+ nullable: true
2666
+ platformAdId: { type: string }
2667
+ platformAdAccountId: { type: string }
2668
+ platformCampaignId: { type: string }
2669
+ platformAdSetId: { type: string }
2670
+ campaignName: { type: string }
2671
+ adSetName: { type: string }
2672
+ creative: { type: object, description: Platform-specific creative data }
2673
+ targeting: { type: object }
2674
+ schedule:
2675
+ type: object
2676
+ nullable: true
2677
+ properties:
2678
+ startDate: { type: string, format: date-time }
2679
+ endDate: { type: string, format: date-time }
2680
+ rejectionReason: { type: string }
2681
+ createdAt: { type: string, format: date-time }
2682
+ updatedAt: { type: string, format: date-time }
2683
+ AdCampaign:
2684
+ type: object
2685
+ properties:
2686
+ platformCampaignId: { type: string }
2687
+ platform: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter] }
2688
+ campaignName: { type: string }
2689
+ status: { type: string, enum: [active, paused, pending_review, rejected, completed, cancelled, error], description: Derived from child ad statuses }
2690
+ adCount: { type: integer }
2691
+ budget:
2692
+ type: object
2693
+ nullable: true
2694
+ properties:
2695
+ amount: { type: number }
2696
+ type: { type: string, enum: [daily, lifetime] }
2697
+ metrics: { $ref: '#/components/schemas/AdMetrics' }
2698
+ platformAdAccountId: { type: string }
2699
+ accountId: { type: string }
2700
+ profileId: { type: string }
2701
+ earliestAd: { type: string, format: date-time }
2702
+ latestAd: { type: string, format: date-time }
2618
2703
  webhooks:
2619
2704
  post.scheduled:
2620
2705
  post:
@@ -5792,6 +5877,15 @@ paths:
5792
5877
  type: string
5793
5878
  format: uri
5794
5879
  description: "Public URL of a custom thumbnail image (JPEG, PNG, or GIF, max 2 MB, recommended 1280x720). Works on any video you own, including existing videos not published through Zernio. The channel must be verified (phone verification) to set custom thumbnails."
5880
+ madeForKids:
5881
+ type: boolean
5882
+ description: "COPPA compliance flag. Set true for child-directed content (restricts comments, notifications, ad targeting)."
5883
+ containsSyntheticMedia:
5884
+ type: boolean
5885
+ description: "AI-generated content disclosure. Set true if the video contains synthetic content that could be mistaken for real. YouTube may add a label."
5886
+ playlistId:
5887
+ type: string
5888
+ description: "YouTube playlist ID to add the video to (e.g. 'PLxxxxxxxxxxxxx'). Use GET /v1/accounts/{id}/youtube-playlists to list available playlists. Only playlists owned by the channel are supported."
5795
5889
  examples:
5796
5890
  post-based:
5797
5891
  summary: Update a video published through Zernio
@@ -17185,3 +17279,602 @@ paths:
17185
17279
  hasMore: { type: boolean }
17186
17280
  '401': { $ref: '#/components/responses/Unauthorized' }
17187
17281
  '404': { $ref: '#/components/responses/NotFound' }
17282
+
17283
+ # ── Ads ──────────────────────────────────────────────────────────────────
17284
+
17285
+ /v1/ads:
17286
+ get:
17287
+ operationId: listAds
17288
+ tags: [Ads]
17289
+ summary: List ads
17290
+ description: Returns a paginated list of ads with cached metrics. Use `source=all` to include externally-synced ads from platform ad managers.
17291
+ security:
17292
+ - bearerAuth: []
17293
+ parameters:
17294
+ - $ref: '#/components/parameters/PageParam'
17295
+ - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 500, default: 50 } }
17296
+ - { name: source, in: query, schema: { type: string, enum: [zernio, all], default: zernio }, description: "zernio = Zernio-created only, all = include external ads" }
17297
+ - { name: status, in: query, schema: { type: string, enum: [active, paused, pending_review, rejected, completed, cancelled, error] } }
17298
+ - { name: platform, in: query, schema: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter] } }
17299
+ - { name: accountId, in: query, schema: { type: string }, description: Social account ID }
17300
+ - { name: profileId, in: query, schema: { type: string }, description: Profile ID }
17301
+ - { name: campaignId, in: query, schema: { type: string }, description: Platform campaign ID (filter ads within a campaign) }
17302
+ responses:
17303
+ '200':
17304
+ description: Paginated ads
17305
+ content:
17306
+ application/json:
17307
+ schema:
17308
+ type: object
17309
+ properties:
17310
+ ads:
17311
+ type: array
17312
+ items: { $ref: '#/components/schemas/Ad' }
17313
+ pagination: { $ref: '#/components/schemas/Pagination' }
17314
+ '401': { $ref: '#/components/responses/Unauthorized' }
17315
+ '403':
17316
+ description: Ads add-on required
17317
+
17318
+ /v1/ads/campaigns:
17319
+ get:
17320
+ operationId: listAdCampaigns
17321
+ tags: [Ad Campaigns]
17322
+ summary: List campaigns with aggregate metrics
17323
+ description: |
17324
+ Returns campaigns as virtual aggregations over ad documents grouped by platform campaign ID.
17325
+ Metrics (spend, impressions, clicks, etc.) are summed across all ads in each campaign.
17326
+ Campaign status is derived from child ad statuses (active > pending_review > paused > error > completed > cancelled > rejected).
17327
+ security:
17328
+ - bearerAuth: []
17329
+ parameters:
17330
+ - $ref: '#/components/parameters/PageParam'
17331
+ - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 100, default: 20 } }
17332
+ - { name: source, in: query, schema: { type: string, enum: [zernio, all], default: zernio } }
17333
+ - { name: platform, in: query, schema: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter] } }
17334
+ - { name: status, in: query, schema: { type: string, enum: [active, paused, pending_review, rejected, completed, cancelled, error] }, description: Filter by derived campaign status (post-aggregation) }
17335
+ - { name: adAccountId, in: query, schema: { type: string }, description: Platform ad account ID (e.g. act_123 for Meta) }
17336
+ - { name: accountId, in: query, schema: { type: string }, description: Social account ID }
17337
+ - { name: profileId, in: query, schema: { type: string }, description: Profile ID }
17338
+ responses:
17339
+ '200':
17340
+ description: Paginated campaigns
17341
+ content:
17342
+ application/json:
17343
+ schema:
17344
+ type: object
17345
+ properties:
17346
+ campaigns:
17347
+ type: array
17348
+ items: { $ref: '#/components/schemas/AdCampaign' }
17349
+ pagination: { $ref: '#/components/schemas/Pagination' }
17350
+ '401': { $ref: '#/components/responses/Unauthorized' }
17351
+ '403':
17352
+ description: Ads add-on required
17353
+
17354
+ /v1/ads/campaigns/{campaignId}/status:
17355
+ put:
17356
+ operationId: updateAdCampaignStatus
17357
+ tags: [Ad Campaigns]
17358
+ summary: Pause or resume a campaign
17359
+ description: |
17360
+ Updates the status of all ads in a campaign. Makes one platform API call (not per-ad) since status cascades through the campaign hierarchy.
17361
+ Ads in terminal statuses (rejected, completed, cancelled) are automatically skipped.
17362
+ security:
17363
+ - bearerAuth: []
17364
+ parameters:
17365
+ - { name: campaignId, in: path, required: true, schema: { type: string }, description: Platform campaign ID }
17366
+ requestBody:
17367
+ required: true
17368
+ content:
17369
+ application/json:
17370
+ schema:
17371
+ type: object
17372
+ required: [status, platform]
17373
+ properties:
17374
+ status: { type: string, enum: [active, paused] }
17375
+ platform: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter] }
17376
+ responses:
17377
+ '200':
17378
+ description: Campaign status updated
17379
+ content:
17380
+ application/json:
17381
+ schema:
17382
+ type: object
17383
+ properties:
17384
+ updated: { type: integer, description: Number of ads updated }
17385
+ skipped: { type: integer, description: Number of ads skipped }
17386
+ skippedReasons: { type: array, items: { type: string } }
17387
+ '400':
17388
+ description: Invalid input or campaign spans multiple social accounts
17389
+ '401': { $ref: '#/components/responses/Unauthorized' }
17390
+ '404':
17391
+ description: No ads found for this campaign
17392
+
17393
+ /v1/ads/{adId}:
17394
+ get:
17395
+ operationId: getAd
17396
+ tags: [Ads]
17397
+ summary: Get ad details
17398
+ security:
17399
+ - bearerAuth: []
17400
+ parameters:
17401
+ - { name: adId, in: path, required: true, schema: { type: string } }
17402
+ responses:
17403
+ '200':
17404
+ description: Ad details
17405
+ content:
17406
+ application/json:
17407
+ schema:
17408
+ type: object
17409
+ properties:
17410
+ ad: { $ref: '#/components/schemas/Ad' }
17411
+ '401': { $ref: '#/components/responses/Unauthorized' }
17412
+ '404': { $ref: '#/components/responses/NotFound' }
17413
+ put:
17414
+ operationId: updateAd
17415
+ tags: [Ads]
17416
+ summary: Update ad (pause/resume, budget, targeting, name)
17417
+ description: Update one or more fields on an ad. Status changes and budget updates are propagated to the platform. Targeting updates are Meta-only.
17418
+ security:
17419
+ - bearerAuth: []
17420
+ parameters:
17421
+ - { name: adId, in: path, required: true, schema: { type: string } }
17422
+ requestBody:
17423
+ required: true
17424
+ content:
17425
+ application/json:
17426
+ schema:
17427
+ type: object
17428
+ properties:
17429
+ status: { type: string, enum: [active, paused] }
17430
+ budget:
17431
+ type: object
17432
+ properties:
17433
+ amount: { type: number, description: "Minimum varies by platform: TikTok=$20, Pinterest=$5, others=$1" }
17434
+ type: { type: string, enum: [daily, lifetime] }
17435
+ targeting:
17436
+ type: object
17437
+ description: Meta-only. Targeting updates for other platforms are not supported after creation.
17438
+ properties:
17439
+ ageMin: { type: integer, minimum: 13, maximum: 65 }
17440
+ ageMax: { type: integer, minimum: 13, maximum: 65 }
17441
+ countries: { type: array, items: { type: string } }
17442
+ interests: { type: array, items: { type: string } }
17443
+ name: { type: string }
17444
+ responses:
17445
+ '200':
17446
+ description: Ad updated
17447
+ content:
17448
+ application/json:
17449
+ schema:
17450
+ type: object
17451
+ properties:
17452
+ ad: { $ref: '#/components/schemas/Ad' }
17453
+ message: { type: string }
17454
+ '400':
17455
+ description: Invalid status transition or budget below minimum
17456
+ '401': { $ref: '#/components/responses/Unauthorized' }
17457
+ '404': { $ref: '#/components/responses/NotFound' }
17458
+ delete:
17459
+ operationId: deleteAd
17460
+ tags: [Ads]
17461
+ summary: Cancel an ad
17462
+ description: Cancels the ad on the platform and marks it as cancelled in the database. The ad is preserved for history.
17463
+ security:
17464
+ - bearerAuth: []
17465
+ parameters:
17466
+ - { name: adId, in: path, required: true, schema: { type: string } }
17467
+ responses:
17468
+ '200':
17469
+ description: Ad cancelled
17470
+ content:
17471
+ application/json:
17472
+ schema:
17473
+ type: object
17474
+ properties:
17475
+ message: { type: string }
17476
+ '401': { $ref: '#/components/responses/Unauthorized' }
17477
+ '404': { $ref: '#/components/responses/NotFound' }
17478
+
17479
+ /v1/ads/{adId}/analytics:
17480
+ get:
17481
+ operationId: getAdAnalytics
17482
+ tags: [Ads]
17483
+ summary: Get ad analytics with daily breakdown
17484
+ description: |
17485
+ Returns real-time analytics from the platform API (not cached). Includes summary metrics,
17486
+ daily breakdown, and optional demographic breakdowns (Meta and TikTok only).
17487
+ security:
17488
+ - bearerAuth: []
17489
+ parameters:
17490
+ - { name: adId, in: path, required: true, schema: { type: string } }
17491
+ - name: breakdowns
17492
+ in: query
17493
+ schema: { type: string }
17494
+ description: "Comma-separated breakdown dimensions. Meta: age, gender, country, publisher_platform, device_platform, region. TikTok: gender, age, country_code, platform, ac, language."
17495
+ responses:
17496
+ '200':
17497
+ description: Ad analytics
17498
+ content:
17499
+ application/json:
17500
+ schema:
17501
+ type: object
17502
+ properties:
17503
+ ad:
17504
+ type: object
17505
+ properties:
17506
+ id: { type: string }
17507
+ name: { type: string }
17508
+ platform: { type: string }
17509
+ status: { type: string }
17510
+ analytics:
17511
+ type: object
17512
+ properties:
17513
+ summary: { $ref: '#/components/schemas/AdMetrics' }
17514
+ daily:
17515
+ type: array
17516
+ items:
17517
+ allOf:
17518
+ - { $ref: '#/components/schemas/AdMetrics' }
17519
+ - type: object
17520
+ properties:
17521
+ date: { type: string, format: date }
17522
+ breakdowns:
17523
+ type: object
17524
+ additionalProperties:
17525
+ type: array
17526
+ items: { type: object }
17527
+ '401': { $ref: '#/components/responses/Unauthorized' }
17528
+ '404': { $ref: '#/components/responses/NotFound' }
17529
+
17530
+ /v1/ads/accounts:
17531
+ get:
17532
+ operationId: listAdAccounts
17533
+ tags: [Ads]
17534
+ summary: List ad accounts for a social account
17535
+ description: Returns the platform ad accounts available for the given social account (e.g. Meta ad accounts, TikTok advertiser IDs, Google Ads customer IDs).
17536
+ security:
17537
+ - bearerAuth: []
17538
+ parameters:
17539
+ - { name: accountId, in: query, required: true, schema: { type: string }, description: Social account ID }
17540
+ responses:
17541
+ '200':
17542
+ description: Ad accounts
17543
+ content:
17544
+ application/json:
17545
+ schema:
17546
+ type: object
17547
+ properties:
17548
+ accounts:
17549
+ type: array
17550
+ items:
17551
+ type: object
17552
+ properties:
17553
+ id: { type: string, description: "Platform ad account ID (e.g. act_123)" }
17554
+ name: { type: string }
17555
+ currency: { type: string }
17556
+ status: { type: string }
17557
+ '401': { $ref: '#/components/responses/Unauthorized' }
17558
+
17559
+ /v1/ads/boost:
17560
+ post:
17561
+ operationId: boostPost
17562
+ tags: [Ads]
17563
+ summary: Boost an existing post as a paid ad
17564
+ description: Creates a paid ad campaign from an existing published post. Creates the full platform campaign hierarchy (campaign, ad set, ad).
17565
+ security:
17566
+ - bearerAuth: []
17567
+ requestBody:
17568
+ required: true
17569
+ content:
17570
+ application/json:
17571
+ schema:
17572
+ type: object
17573
+ required: [accountId, adAccountId, name, goal, budget]
17574
+ properties:
17575
+ postId: { type: string, description: Zernio post ID (provide this or platformPostId) }
17576
+ platformPostId: { type: string, description: Platform post ID (alternative to postId) }
17577
+ accountId: { type: string, description: Social account ID }
17578
+ adAccountId: { type: string, description: Platform ad account ID }
17579
+ name: { type: string, maxLength: 255 }
17580
+ goal: { type: string, enum: [engagement, traffic, awareness, video_views] }
17581
+ budget:
17582
+ type: object
17583
+ required: [amount, type]
17584
+ properties:
17585
+ amount: { type: number, description: "Minimum varies: TikTok=$20, Pinterest=$5, others=$1" }
17586
+ type: { type: string, enum: [daily, lifetime] }
17587
+ currency: { type: string, example: USD }
17588
+ schedule:
17589
+ type: object
17590
+ properties:
17591
+ startDate: { type: string, format: date-time }
17592
+ endDate: { type: string, format: date-time, description: Required for lifetime budgets }
17593
+ targeting:
17594
+ type: object
17595
+ properties:
17596
+ ageMin: { type: integer, minimum: 13, maximum: 65 }
17597
+ ageMax: { type: integer, minimum: 13, maximum: 65 }
17598
+ countries: { type: array, items: { type: string } }
17599
+ interests: { type: array, items: { type: string } }
17600
+ responses:
17601
+ '201':
17602
+ description: Ad created
17603
+ content:
17604
+ application/json:
17605
+ schema:
17606
+ type: object
17607
+ properties:
17608
+ ad: { $ref: '#/components/schemas/Ad' }
17609
+ message: { type: string }
17610
+ '400':
17611
+ description: Missing required fields or invalid values
17612
+ '401': { $ref: '#/components/responses/Unauthorized' }
17613
+ '403':
17614
+ description: Ads add-on required
17615
+
17616
+ /v1/ads/create:
17617
+ post:
17618
+ operationId: createStandaloneAd
17619
+ tags: [Ads]
17620
+ summary: Create a standalone ad with custom creative
17621
+ description: Creates a paid ad with custom creative (headline, body, image/video, link). Creates the full platform campaign hierarchy.
17622
+ security:
17623
+ - bearerAuth: []
17624
+ requestBody:
17625
+ required: true
17626
+ content:
17627
+ application/json:
17628
+ schema:
17629
+ type: object
17630
+ required: [accountId, adAccountId, name, goal, budgetAmount, budgetType, body, imageUrl]
17631
+ properties:
17632
+ accountId: { type: string }
17633
+ adAccountId: { type: string }
17634
+ name: { type: string, maxLength: 255 }
17635
+ goal: { type: string, enum: [engagement, traffic, awareness, video_views] }
17636
+ budgetAmount: { type: number }
17637
+ budgetType: { type: string, enum: [daily, lifetime] }
17638
+ currency: { type: string }
17639
+ headline: { type: string, description: "Required for most platforms. Max: Meta=255, Google=30, Pinterest=100" }
17640
+ body: { type: string, description: "Max: Google=90, Pinterest=500" }
17641
+ callToAction: { type: string, enum: [LEARN_MORE, SHOP_NOW, SIGN_UP, BOOK_TRAVEL, CONTACT_US, DOWNLOAD, GET_OFFER, GET_QUOTE, SUBSCRIBE, WATCH_MORE], description: Meta only }
17642
+ linkUrl: { type: string, format: uri }
17643
+ imageUrl: { type: string, format: uri, description: Image URL (or video URL for TikTok) }
17644
+ countries: { type: array, items: { type: string } }
17645
+ ageMin: { type: integer, minimum: 13, maximum: 65 }
17646
+ ageMax: { type: integer, minimum: 13, maximum: 65 }
17647
+ interests: { type: array, items: { type: string } }
17648
+ endDate: { type: string, format: date-time, description: Required for lifetime budgets }
17649
+ audienceId: { type: string, description: Custom audience ID for targeting }
17650
+ campaignType: { type: string, enum: [display, search], default: display, description: Google only }
17651
+ keywords: { type: array, items: { type: string }, description: Google Search only }
17652
+ responses:
17653
+ '201':
17654
+ description: Ad created
17655
+ content:
17656
+ application/json:
17657
+ schema:
17658
+ type: object
17659
+ properties:
17660
+ ad: { $ref: '#/components/schemas/Ad' }
17661
+ message: { type: string }
17662
+ '400':
17663
+ description: Missing required fields or invalid values
17664
+ '401': { $ref: '#/components/responses/Unauthorized' }
17665
+ '403':
17666
+ description: Ads add-on required
17667
+
17668
+ /v1/ads/sync:
17669
+ post:
17670
+ operationId: syncExternalAds
17671
+ tags: [Ads]
17672
+ summary: Sync external ads from platform ad managers
17673
+ description: Discovers and imports ads created outside Zernio (e.g. in Meta Ads Manager, Google Ads). Upserts new ads and updates metrics/status for existing ones. Also runs automatically every 30 minutes.
17674
+ security:
17675
+ - bearerAuth: []
17676
+ responses:
17677
+ '200':
17678
+ description: Sync completed
17679
+ content:
17680
+ application/json:
17681
+ schema:
17682
+ type: object
17683
+ properties:
17684
+ success: { type: boolean }
17685
+ synced: { type: integer, description: New ads imported }
17686
+ skipped: { type: integer, description: Already-synced ads updated }
17687
+ errors: { type: integer, description: Failed ad imports }
17688
+ '401': { $ref: '#/components/responses/Unauthorized' }
17689
+ '403':
17690
+ description: Ads add-on required
17691
+
17692
+ /v1/ads/interests:
17693
+ get:
17694
+ operationId: searchAdInterests
17695
+ tags: [Ads]
17696
+ summary: Search targeting interests
17697
+ description: Search for interest-based targeting options available on the platform.
17698
+ security:
17699
+ - bearerAuth: []
17700
+ parameters:
17701
+ - { name: q, in: query, required: true, schema: { type: string }, description: Search query }
17702
+ - { name: accountId, in: query, required: true, schema: { type: string }, description: Social account ID }
17703
+ responses:
17704
+ '200':
17705
+ description: Matching interests
17706
+ content:
17707
+ application/json:
17708
+ schema:
17709
+ type: object
17710
+ properties:
17711
+ interests:
17712
+ type: array
17713
+ items:
17714
+ type: object
17715
+ properties:
17716
+ id: { type: string }
17717
+ name: { type: string }
17718
+ category: { type: string }
17719
+ '401': { $ref: '#/components/responses/Unauthorized' }
17720
+
17721
+ /v1/ads/audiences:
17722
+ get:
17723
+ operationId: listAdAudiences
17724
+ tags: [Ad Audiences]
17725
+ summary: List custom audiences
17726
+ description: Returns custom audiences for the given ad account. Supports Meta, Google, TikTok, and Pinterest.
17727
+ security:
17728
+ - bearerAuth: []
17729
+ parameters:
17730
+ - { name: accountId, in: query, required: true, schema: { type: string }, description: Social account ID }
17731
+ - { name: adAccountId, in: query, required: true, schema: { type: string }, description: Platform ad account ID }
17732
+ - { name: platform, in: query, schema: { type: string, enum: [facebook, instagram, googleads, tiktok, pinterest] } }
17733
+ responses:
17734
+ '200':
17735
+ description: Audiences
17736
+ content:
17737
+ application/json:
17738
+ schema:
17739
+ type: object
17740
+ properties:
17741
+ audiences:
17742
+ type: array
17743
+ items:
17744
+ type: object
17745
+ properties:
17746
+ id: { type: string, nullable: true }
17747
+ platformAudienceId: { type: string }
17748
+ name: { type: string }
17749
+ description: { type: string }
17750
+ type: { type: string, enum: [customer_list, website, lookalike] }
17751
+ platform: { type: string }
17752
+ size: { type: integer }
17753
+ status: { type: string }
17754
+ '401': { $ref: '#/components/responses/Unauthorized' }
17755
+ post:
17756
+ operationId: createAdAudience
17757
+ tags: [Ad Audiences]
17758
+ summary: Create a custom audience (Meta only)
17759
+ description: Create a customer list, website retargeting, or lookalike audience on Meta (Facebook/Instagram).
17760
+ security:
17761
+ - bearerAuth: []
17762
+ requestBody:
17763
+ required: true
17764
+ content:
17765
+ application/json:
17766
+ schema:
17767
+ type: object
17768
+ required: [accountId, adAccountId, name, type]
17769
+ properties:
17770
+ accountId: { type: string }
17771
+ adAccountId: { type: string, description: "Must start with act_" }
17772
+ name: { type: string, maxLength: 255 }
17773
+ description: { type: string }
17774
+ type: { type: string, enum: [customer_list, website, lookalike] }
17775
+ pixelId: { type: string, description: Required for website audiences }
17776
+ retentionDays: { type: integer, minimum: 1, maximum: 180, description: Required for website audiences }
17777
+ sourceAudienceId: { type: string, description: Required for lookalike audiences }
17778
+ country: { type: string, description: "2-letter code, required for lookalike audiences" }
17779
+ ratio: { type: number, minimum: 0.01, maximum: 0.20, description: Required for lookalike audiences }
17780
+ responses:
17781
+ '201':
17782
+ description: Audience created
17783
+ content:
17784
+ application/json:
17785
+ schema:
17786
+ type: object
17787
+ properties:
17788
+ audience: { type: object }
17789
+ message: { type: string }
17790
+ '400':
17791
+ description: Missing required fields
17792
+ '401': { $ref: '#/components/responses/Unauthorized' }
17793
+ '403':
17794
+ description: Ads add-on required
17795
+
17796
+ /v1/ads/audiences/{audienceId}:
17797
+ get:
17798
+ operationId: getAdAudience
17799
+ tags: [Ad Audiences]
17800
+ summary: Get audience details
17801
+ description: Returns the local audience record and fresh data from Meta (if available).
17802
+ security:
17803
+ - bearerAuth: []
17804
+ parameters:
17805
+ - { name: audienceId, in: path, required: true, schema: { type: string } }
17806
+ responses:
17807
+ '200':
17808
+ description: Audience details
17809
+ content:
17810
+ application/json:
17811
+ schema:
17812
+ type: object
17813
+ properties:
17814
+ audience: { type: object }
17815
+ metaData: { type: object, nullable: true, description: Fresh data from Meta API }
17816
+ '401': { $ref: '#/components/responses/Unauthorized' }
17817
+ '404': { $ref: '#/components/responses/NotFound' }
17818
+ delete:
17819
+ operationId: deleteAdAudience
17820
+ tags: [Ad Audiences]
17821
+ summary: Delete a custom audience
17822
+ description: Deletes the audience from both Meta and the local database.
17823
+ security:
17824
+ - bearerAuth: []
17825
+ parameters:
17826
+ - { name: audienceId, in: path, required: true, schema: { type: string } }
17827
+ responses:
17828
+ '200':
17829
+ description: Audience deleted
17830
+ content:
17831
+ application/json:
17832
+ schema:
17833
+ type: object
17834
+ properties:
17835
+ message: { type: string }
17836
+ '401': { $ref: '#/components/responses/Unauthorized' }
17837
+ '404': { $ref: '#/components/responses/NotFound' }
17838
+
17839
+ /v1/ads/audiences/{audienceId}/users:
17840
+ post:
17841
+ operationId: addUsersToAdAudience
17842
+ tags: [Ad Audiences]
17843
+ summary: Add users to a customer list audience
17844
+ description: Upload user data (emails and/or phone numbers) to a customer_list audience. Data is SHA256-hashed server-side before sending to Meta. Max 10,000 users per request.
17845
+ security:
17846
+ - bearerAuth: []
17847
+ parameters:
17848
+ - { name: audienceId, in: path, required: true, schema: { type: string } }
17849
+ requestBody:
17850
+ required: true
17851
+ content:
17852
+ application/json:
17853
+ schema:
17854
+ type: object
17855
+ required: [users]
17856
+ properties:
17857
+ users:
17858
+ type: array
17859
+ maxItems: 10000
17860
+ items:
17861
+ type: object
17862
+ properties:
17863
+ email: { type: string, format: email }
17864
+ phone: { type: string }
17865
+ description: Each user must have at least email or phone
17866
+ responses:
17867
+ '200':
17868
+ description: Users added
17869
+ content:
17870
+ application/json:
17871
+ schema:
17872
+ type: object
17873
+ properties:
17874
+ message: { type: string }
17875
+ numReceived: { type: integer }
17876
+ numInvalid: { type: integer }
17877
+ '400':
17878
+ description: Invalid input or not a customer_list audience
17879
+ '401': { $ref: '#/components/responses/Unauthorized' }
17880
+ '404': { $ref: '#/components/responses/NotFound' }