late-sdk 0.0.771 → 0.0.773

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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +7 -0
  3. data/docs/AdCampaignsApi.md +72 -0
  4. data/docs/AnalyticsApi.md +2 -2
  5. data/docs/AttachCampaignAssets201Response.md +24 -0
  6. data/docs/AttachCampaignAssetsRequest.md +24 -0
  7. data/docs/AttachCampaignAssetsRequestSitelinksInner.md +24 -0
  8. data/docs/AttachCampaignAssetsRequestStructuredSnippetsInner.md +20 -0
  9. data/docs/CreateInboxConversationRequest.md +3 -1
  10. data/docs/CreateInboxConversationRequestTemplateButtonParamsInner.md +22 -0
  11. data/docs/CreateStandaloneAdRequest.md +4 -0
  12. data/docs/CreateStandaloneAdRequestStructuredSnippetsInner.md +20 -0
  13. data/docs/GetInboxConversationMessages200ResponseMessagesInner.md +4 -2
  14. data/docs/MessagesApi.md +1 -1
  15. data/docs/PostAnalytics.md +4 -0
  16. data/docs/TargetingSpec.md +2 -2
  17. data/docs/WebhookPayloadMessageMessage.md +3 -1
  18. data/docs/WebhookPayloadMessageSentMessage.md +4 -2
  19. data/lib/zernio-sdk/api/ad_campaigns_api.rb +74 -0
  20. data/lib/zernio-sdk/api/analytics_api.rb +3 -3
  21. data/lib/zernio-sdk/api/messages_api.rb +2 -2
  22. data/lib/zernio-sdk/models/ad_tree_campaign_optimization_goal.rb +1 -0
  23. data/lib/zernio-sdk/models/attach_campaign_assets201_response.rb +180 -0
  24. data/lib/zernio-sdk/models/attach_campaign_assets_request.rb +283 -0
  25. data/lib/zernio-sdk/models/attach_campaign_assets_request_sitelinks_inner.rb +282 -0
  26. data/lib/zernio-sdk/models/attach_campaign_assets_request_structured_snippets_inner.rb +234 -0
  27. data/lib/zernio-sdk/models/create_inbox_conversation_request.rb +33 -2
  28. data/lib/zernio-sdk/models/create_inbox_conversation_request_template_button_params_inner.rb +270 -0
  29. data/lib/zernio-sdk/models/create_standalone_ad_request.rb +81 -1
  30. data/lib/zernio-sdk/models/create_standalone_ad_request_structured_snippets_inner.rb +235 -0
  31. data/lib/zernio-sdk/models/get_inbox_conversation_messages200_response_messages_inner.rb +28 -5
  32. data/lib/zernio-sdk/models/post_analytics.rb +21 -1
  33. data/lib/zernio-sdk/models/targeting_spec.rb +2 -0
  34. data/lib/zernio-sdk/models/webhook_payload_message_message.rb +27 -4
  35. data/lib/zernio-sdk/models/webhook_payload_message_sent_message.rb +28 -5
  36. data/lib/zernio-sdk/version.rb +1 -1
  37. data/lib/zernio-sdk.rb +6 -0
  38. data/openapi.yaml +211 -11
  39. data/spec/api/ad_campaigns_api_spec.rb +13 -0
  40. data/spec/api/analytics_api_spec.rb +1 -1
  41. data/spec/api/messages_api_spec.rb +1 -1
  42. data/spec/models/attach_campaign_assets201_response_spec.rb +54 -0
  43. data/spec/models/attach_campaign_assets_request_sitelinks_inner_spec.rb +54 -0
  44. data/spec/models/attach_campaign_assets_request_spec.rb +54 -0
  45. data/spec/models/attach_campaign_assets_request_structured_snippets_inner_spec.rb +46 -0
  46. data/spec/models/create_inbox_conversation_request_spec.rb +6 -0
  47. data/spec/models/create_inbox_conversation_request_template_button_params_inner_spec.rb +52 -0
  48. data/spec/models/create_standalone_ad_request_spec.rb +12 -0
  49. data/spec/models/create_standalone_ad_request_structured_snippets_inner_spec.rb +46 -0
  50. data/spec/models/get_inbox_conversation_messages200_response_messages_inner_spec.rb +10 -0
  51. data/spec/models/post_analytics_spec.rb +12 -0
  52. data/spec/models/webhook_payload_message_message_spec.rb +10 -0
  53. data/spec/models/webhook_payload_message_sent_message_spec.rb +10 -0
  54. data/zernio-sdk-0.0.773.gem +0 -0
  55. metadata +26 -2
  56. data/zernio-sdk-0.0.771.gem +0 -0
data/openapi.yaml CHANGED
@@ -3663,6 +3663,14 @@ components:
3663
3663
  description: 'When the message was sent, as reported by the platform and passed through unmodified. Full ISO 8601 date-time: Instagram and Facebook carry millisecond precision, while some platforms (for example WhatsApp and Telegram) report whole seconds. Use this field as the chronological ordering key. If two messages share the same value, fetch the conversation messages with sortOrder=desc for the deterministic order.'
3664
3664
  isRead:
3665
3665
  type: boolean
3666
+ sentVia:
3667
+ type: [string, "null"]
3668
+ enum: [human, api, broadcast, sequence, workflow, comment_automation, bulk-api, null]
3669
+ description: |
3670
+ Which Zernio surface produced the message. Always present and
3671
+ always `null` on this event, since nobody on our side produced an
3672
+ inbound message; it is only informative on `message.sent`, which
3673
+ documents the vocabulary.
3666
3674
  conversation:
3667
3675
  $ref: '#/components/schemas/InboxWebhookConversation'
3668
3676
  account:
@@ -4020,7 +4028,23 @@ components:
4020
4028
  source:
4021
4029
  type: string
4022
4030
  enum: [whatsapp_business_app, cloud_api]
4023
- description: 'WhatsApp send origin. whatsapp_business_app when sent from the WhatsApp Business phone app on a Coexistence number; cloud_api when sent through Zernio (dashboard, API, or broadcasts). Absent on non-WhatsApp platforms. This is not the inbox metadata.source lineage field.'
4031
+ description: 'WhatsApp send origin. whatsapp_business_app when sent from the WhatsApp Business phone app on a Coexistence number; cloud_api when sent through Zernio (dashboard, API, or broadcasts). Absent on non-WhatsApp platforms. Says where WhatsApp saw the send come from, not which Zernio surface produced it: read sentVia for that.'
4032
+ sentVia:
4033
+ type: [string, "null"]
4034
+ enum: [human, api, broadcast, sequence, workflow, comment_automation, bulk-api, null]
4035
+ description: |
4036
+ Which Zernio surface produced this message: `human` (an operator
4037
+ in the Zernio inbox), `api` (a call to this API), `broadcast`,
4038
+ `sequence`, `workflow`, `comment_automation`, or `bulk-api`
4039
+ (POST /v1/whatsapp/bulk). Same vocabulary as the `source` filter
4040
+ on the inbox analytics endpoints, and the same value a later
4041
+ GET on this message returns.
4042
+
4043
+ Always present, and `null` whenever the lineage is unknown: a
4044
+ message sent from the platform's own app, and every message
4045
+ stored before this field shipped (2026-08). Existing messages
4046
+ are NOT backfilled, so treat `null` as "unknown", never as
4047
+ "sent by a human".
4024
4048
  conversation:
4025
4049
  $ref: '#/components/schemas/InboxWebhookConversation'
4026
4050
  account:
@@ -7159,6 +7183,8 @@ components:
7159
7183
  follows: { type: integer, example: 0, description: 'Instagram feed posts and stories only: organic accounts that started following from this post. 0 for reels and other platforms.' }
7160
7184
  igReelsAvgWatchTime: { type: integer, example: 0, description: 'Instagram Reels only: average watch time per play, in milliseconds. 0 for non-Reels media and other platforms.' }
7161
7185
  igReelsVideoViewTotalTime: { type: integer, example: 0, description: 'Instagram Reels only: total watch time including replays, in milliseconds. 0 for non-Reels media and other platforms.' }
7186
+ reelsSkipRate: { type: number, example: 0, description: 'Instagram Reels only: the rate of initial views that skipped the reel within its first 3 seconds, as reported by Meta. Passed through exactly as Meta reports it, with no rescaling, so do not assume a 0-1 share. Meta labels the metric estimated and in development, so it can move between syncs. 0 for non-Reels media and other platforms. When a post is published to several accounts, the aggregate is weighted by views.' }
7187
+ reposts: { type: integer, example: 0, description: 'Instagram only: reposts of the media by other users, minus deleted reposts. Available on feed posts, reels and stories. 0 for other platforms, including Threads, where reposts are counted in shares instead.' }
7162
7188
  videoDurationSeconds: { type: [integer, "null"], example: 30, description: 'Video length in seconds. Currently Instagram Reels only; combine with igReelsAvgWatchTime (ms) to estimate retention. Null when unknown (other platforms, non-video media, or when Instagram does not expose the media URL, e.g. reels with copyrighted audio).' }
7163
7189
  engagementRate: { type: number, example: 6.59, description: 'Percentage, rounded to 2 decimals: (likes + comments + shares + saves) / (impressions or reach or views) * 100. Clicks and follows are never counted. The denominator is the FIRST of impressions, reach, views that is non-zero, so it is not the same basis on every post: a post with impressions divides by impressions, one without falls back to reach, then to views. If you need a single consistent basis (e.g. interactions / reach), compute it from the raw fields above. The engagementRate on the LinkedIn account endpoints is a different formula.' }
7164
7190
  lastUpdated: { type: string, format: date-time }
@@ -8186,8 +8212,8 @@ components:
8186
8212
  distanceUnit: { type: string, enum: [mile, kilometer] }
8187
8213
  name: { type: string }
8188
8214
  address: { type: string, description: "Optional label, sent to Meta as `address_string`. latitude/longitude take precedence for the pin location." }
8189
- ageMin: { type: integer, minimum: 13, maximum: 100 }
8190
- ageMax: { type: integer, minimum: 13, maximum: 100 }
8215
+ ageMin: { type: integer, minimum: 13, maximum: 100, description: "Minimum age. Applied on Meta, TikTok and Pinterest; ignored on Google, LinkedIn and X. Each platform clamps to its own range: Meta and Pinterest effectively cap at 65 (65 = 65+), TikTok maps up to 100. Pinterest has no under-18 bucket, so an ageMin below 18 starts at 18 there." }
8216
+ ageMax: { type: integer, minimum: 13, maximum: 100, description: "Maximum age. Same per-platform application and clamping as ageMin." }
8191
8217
  gender: { type: string, enum: [all, male, female], description: "Restrict by gender. 'all' (default) targets everyone. Applied on Meta, TikTok and Pinterest. Ignored on Google, LinkedIn and X." }
8192
8218
  incomeTier:
8193
8219
  type: string
@@ -8552,8 +8578,12 @@ components:
8552
8578
  description: "Google-only. Raw campaign.advertising_channel_type (SEARCH, PERFORMANCE_MAX, LOCAL_SERVICES, VIDEO, DEMAND_GEN, DISPLAY, SHOPPING, ...). Serving surface, distinct from platformObjective (advertiser intent). Null/absent for non-Google platforms."
8553
8579
  platformObjective: { type: [string, "null"], description: "Raw Meta campaign objective (e.g. OUTCOME_SALES, OUTCOME_LEADS, OUTCOME_TRAFFIC)" }
8554
8580
  optimizationGoal:
8555
- type: [string, array]
8556
- items: { type: string }
8581
+ # anyOf, not type: [string, array]: hey-api resolves a type-array carrying items
8582
+ # through the array branch and drops the string one (@zernio/node 0.2.640).
8583
+ anyOf:
8584
+ - type: string
8585
+ - type: array
8586
+ items: { type: string }
8557
8587
  description: 'A single string when every ad set shares one optimization goal; a JSON array of the distinct goals when ad sets differ (never a comma-joined string); array element order is not guaranteed, treat it as an unordered set; the key is absent when no ad set carries a goal. Meta: e.g. OFFSITE_CONVERSIONS, VALUE, LEAD_GENERATION. LinkedIn: the campaign optimizationTargetType (e.g. MAX_CLICK, MAX_IMPRESSION, NONE); `NONE` with a manual costType is a campaign LinkedIn will not deliver.'
8558
8588
  bidStrategy:
8559
8589
  anyOf:
@@ -8630,8 +8660,12 @@ components:
8630
8660
  description: "Google-only. Raw campaign.advertising_channel_type. See AdTreeCampaign.advertisingChannelType."
8631
8661
  platformObjective: { type: [string, "null"], description: "Raw Meta campaign objective (e.g. OUTCOME_SALES, OUTCOME_LEADS, OUTCOME_TRAFFIC)" }
8632
8662
  optimizationGoal:
8633
- type: [string, array]
8634
- items: { type: string }
8663
+ # anyOf, not type: [string, array]: hey-api resolves a type-array carrying items
8664
+ # through the array branch and drops the string one (@zernio/node 0.2.640).
8665
+ anyOf:
8666
+ - type: string
8667
+ - type: array
8668
+ items: { type: string }
8635
8669
  description: 'A single string when every ad set shares one optimization goal; a JSON array of the distinct goals when ad sets differ (never a comma-joined string); array element order is not guaranteed, treat it as an unordered set; the key is absent when no ad set carries a goal. Meta: e.g. OFFSITE_CONVERSIONS, VALUE, LEAD_GENERATION. LinkedIn: the campaign optimizationTargetType (e.g. MAX_CLICK, MAX_IMPRESSION, NONE); `NONE` with a manual costType is a campaign LinkedIn will not deliver.'
8636
8670
  bidStrategy:
8637
8671
  anyOf:
@@ -10443,8 +10477,8 @@ paths:
10443
10477
  description: Page number (default 1)
10444
10478
  - name: sortBy
10445
10479
  in: query
10446
- schema: { type: string, enum: [date, engagement, impressions, reach, likes, comments, shares, saves, clicks, views, follows], default: date }
10447
- description: Sort by date, engagement, or a specific metric
10480
+ schema: { type: string, enum: [date, engagement, impressions, reach, likes, comments, shares, saves, clicks, views, follows, ig_reels_avg_watch_time, ig_reels_video_view_total_time, reposts, reels_skip_rate], default: date }
10481
+ description: 'Sort by date, engagement, or a specific metric. Instagram-only metrics (follows, reposts, reels_skip_rate, ig_reels_*) sort posts with no value as 0.'
10448
10482
  - name: order
10449
10483
  in: query
10450
10484
  schema: { type: string, enum: [asc, desc], default: desc }
@@ -25576,7 +25610,7 @@ paths:
25576
25610
 
25577
25611
  Slack: pass a workspace member id as participantId (list them with GET /v1/accounts/{accountId}/slack-members). Zernio opens the DM channel with that member and sends the message; the thread then behaves like any other Slack conversation in the inbox. The member must belong to the connected workspace.
25578
25612
 
25579
- WhatsApp: this is the endpoint for sending an approved template message to a phone number. Provide templateName, templateLanguage, and templateParams (variable values for the text header, body and dynamic URL buttons, in that order), with the recipient phone in participantId. A template is required because WhatsApp does not permit freeform messages to open a conversation; a missing template returns TEMPLATE_REQUIRED. Templates with media headers (image, video, document) are handled automatically: Zernio reads the approved template definition and fills the header at send time with the template's approved sample asset. To send a DIFFERENT asset per message (e.g. a distinct invoice PDF for each recipient), pass the headerMedia field with a public link (or a Meta media id); it overrides the sample for that send. Calling this for a number you already have a thread with simply sends the template into that thread, which also makes it the way to re-engage a contact after the 24-hour customer-service window has closed. Once the recipient replies (opening the 24h window), send freeform messages with the send-message endpoint (POST /v1/inbox/conversations/{conversationId}/messages). Template fields are accepted on the JSON body only, not on multipart requests. Alternatively, WhatsApp Business Accounts eligible for Meta Direct Send can open a conversation with a business-initiated utility text message and no template: pass category: 'utility' together with message (and no templateName). See the category field below.
25613
+ WhatsApp: this is the endpoint for sending an approved template message to a phone number. Provide templateName, templateLanguage, and templateParams (variable values for the text header, body and dynamic URL buttons, in that order), with the recipient phone in participantId. A template is required because WhatsApp does not permit freeform messages to open a conversation; a missing template returns TEMPLATE_REQUIRED. Templates with media headers (image, video, document) are handled automatically: Zernio reads the approved template definition and fills the header at send time with the template's approved sample asset. To send a DIFFERENT asset per message (e.g. a distinct invoice PDF for each recipient), pass the headerMedia field with a public link (or a Meta media id); it overrides the sample for that send. A button that carries its own value at send time (a copy-code button holding a Pix payment code or a coupon, a flow token) is sent with templateButtonParams, addressed by the button's index; templateParams covers text variables and dynamic URL buttons only. Calling this for a number you already have a thread with simply sends the template into that thread, which also makes it the way to re-engage a contact after the 24-hour customer-service window has closed. Once the recipient replies (opening the 24h window), send freeform messages with the send-message endpoint (POST /v1/inbox/conversations/{conversationId}/messages). Template fields are accepted on the JSON body only, not on multipart requests. Alternatively, WhatsApp Business Accounts eligible for Meta Direct Send can open a conversation with a business-initiated utility text message and no template: pass category: 'utility' together with message (and no templateName). See the category field below.
25580
25614
 
25581
25615
  DM eligibility (X/Twitter): Before sending, the endpoint checks if the recipient accepts DMs from your account (via the receives_your_dm field). If not, a 422 error with code DM_NOT_ALLOWED is returned. You can skip this check with skipDmCheck: true if you have already verified eligibility.
25582
25616
 
@@ -25651,7 +25685,42 @@ paths:
25651
25685
  {{1}}, {{2}} plus a URL button https://example.com/{{1}} takes three values:
25652
25686
  [body1, body2, buttonSuffix]. Media headers (image, video, document) are filled
25653
25687
  automatically from the approved template and take no value here (use headerMedia
25654
- to override the header asset per send).
25688
+ to override the header asset per send). Buttons that are not dynamic-URL buttons
25689
+ (copy-code, flow) take no value here either; use templateButtonParams.
25690
+ templateButtonParams:
25691
+ type: array
25692
+ maxItems: 10
25693
+ description: >-
25694
+ WhatsApp only. Values for template buttons that carry one at send time, each
25695
+ addressed by the button's position in the approved template. This is the only
25696
+ way to send a copy-code button's payload (a Pix payment code, a coupon) or a
25697
+ flow token, because templateParams is a flat array of text variables and covers
25698
+ dynamic URL buttons only. Supplying a button here overrides whatever
25699
+ templateParams would have derived for that same index, so the send never
25700
+ carries one button twice; repeating an index within this array is rejected
25701
+ with 400. Each index must name a button of the matching kind on the approved
25702
+ template, which is also checked before the send and returns 400
25703
+ (INVALID_TEMPLATE_BUTTON_PARAM) rather than a Meta rejection.
25704
+ items:
25705
+ type: object
25706
+ required: [index, subType, value]
25707
+ properties:
25708
+ index:
25709
+ type: integer
25710
+ minimum: 0
25711
+ maximum: 9
25712
+ description: 'Zero-based position of the button in the approved template''s buttons.'
25713
+ subType:
25714
+ type: string
25715
+ enum: [url, copy_code, flow]
25716
+ description: >-
25717
+ The button kind, which decides how the value is sent: copy_code sends it
25718
+ as the coupon_code payload, flow as the flow token, url as the dynamic
25719
+ suffix appended to the button's base URL.
25720
+ value:
25721
+ type: string
25722
+ minLength: 1
25723
+ description: 'The value to send (e.g. the Pix copy-and-paste code for a copy_code button).'
25655
25724
  headerMedia:
25656
25725
  type: object
25657
25726
  description: >-
@@ -26265,7 +26334,26 @@ paths:
26265
26334
  `waInteractive` (a compact descriptor of WhatsApp interactive
26266
26335
  content sent: buttons / list / cta_url / flow / location_request),
26267
26336
  and for inbound interactive taps `interactiveType` / `interactiveId`.
26337
+ It can also carry `source` (`whatsapp_business_app` /
26338
+ `coexistence_history` on a WhatsApp Coexistence number, `bulk-api` on
26339
+ a POST /v1/whatsapp/bulk send), which is where the message reached us
26340
+ from rather than who produced it: read `sentVia` for that.
26268
26341
  additionalProperties: true
26342
+ sentVia:
26343
+ type: [string, "null"]
26344
+ enum: [human, api, broadcast, sequence, workflow, comment_automation, bulk-api, null]
26345
+ description: |
26346
+ Which Zernio surface produced this outgoing message: `human` (an
26347
+ operator in the Zernio inbox), `api` (a call to this API),
26348
+ `broadcast`, `sequence`, `workflow`, `comment_automation`, or
26349
+ `bulk-api` (POST /v1/whatsapp/bulk). Same vocabulary as the `source`
26350
+ filter on the inbox analytics endpoints.
26351
+
26352
+ Always present, and `null` whenever the lineage is unknown: every
26353
+ incoming message, any outgoing message sent from the platform's own
26354
+ app, and every message stored before this field shipped
26355
+ (2026-08). Existing messages are NOT backfilled, so treat `null`
26356
+ as "unknown", never as "sent by a human".
26269
26357
  lastUpdated: { type: string, format: date-time }
26270
26358
  '400': { $ref: '#/components/responses/BadRequest' }
26271
26359
  '401': { $ref: '#/components/responses/Unauthorized' }
@@ -40508,6 +40596,85 @@ paths:
40508
40596
  '401': { $ref: '#/components/responses/Unauthorized' }
40509
40597
  '404': { description: Ad not found }
40510
40598
 
40599
+ /v1/ads/campaigns/{campaignId}/assets:
40600
+ post:
40601
+ x-resource-group: "ads"
40602
+ operationId: attachCampaignAssets
40603
+ tags: ["Ad Campaigns"]
40604
+ x-platforms: ["google"]
40605
+ summary: Attach extension assets to a Google Search campaign
40606
+ description: |-
40607
+ Attach sitelinks, callouts and/or structured snippets to an already-existing Google
40608
+ Search campaign — the same builders POST /v1/ads/create uses, but without rebuilding
40609
+ the hierarchy. At least one of sitelinks, callouts or structuredSnippets is required.
40610
+
40611
+ Google-only. Other platforms have no equivalent extension surface and return 501.
40612
+
40613
+ Approval status is Google-async; poll `asset.policy_summary` after review. Assets
40614
+ stay in the account library even if the campaign is later deleted.
40615
+ security:
40616
+ - bearerAuth: []
40617
+ parameters:
40618
+ - { name: campaignId, in: path, required: true, schema: { type: string }, description: "Numeric Google platform campaign id." }
40619
+ requestBody:
40620
+ required: true
40621
+ content:
40622
+ application/json:
40623
+ schema:
40624
+ type: object
40625
+ required: [accountId]
40626
+ properties:
40627
+ accountId: { type: string, description: "Zernio Google Ads SocialAccount id — resolves the customer id + refresh token." }
40628
+ sitelinks:
40629
+ type: array
40630
+ minItems: 2
40631
+ maxItems: 20
40632
+ description: "See POST /v1/ads/create sitelinks — same shape."
40633
+ items:
40634
+ type: object
40635
+ required: [text, linkUrl]
40636
+ properties:
40637
+ text: { type: string, minLength: 1, maxLength: 25 }
40638
+ linkUrl: { type: string, format: uri }
40639
+ description1: { type: string, minLength: 1, maxLength: 35 }
40640
+ description2: { type: string, minLength: 1, maxLength: 35 }
40641
+ callouts:
40642
+ type: array
40643
+ minItems: 1
40644
+ maxItems: 20
40645
+ items: { type: string, minLength: 1, maxLength: 25 }
40646
+ structuredSnippets:
40647
+ type: array
40648
+ minItems: 1
40649
+ maxItems: 20
40650
+ items:
40651
+ type: object
40652
+ required: [header, values]
40653
+ properties:
40654
+ header:
40655
+ type: string
40656
+ enum: [Amenities, Brands, Courses, Degree programs, Destinations, Featured hotels, Insurance coverage, Models, Neighborhoods, Service catalog, Shows, Styles, Types]
40657
+ values:
40658
+ type: array
40659
+ minItems: 3
40660
+ maxItems: 10
40661
+ items: { type: string, minLength: 1, maxLength: 25 }
40662
+ responses:
40663
+ '201':
40664
+ description: Assets attached
40665
+ content:
40666
+ application/json:
40667
+ schema:
40668
+ type: object
40669
+ properties:
40670
+ campaignId: { type: string }
40671
+ sitelinkAssetResourceNames: { type: array, items: { type: string } }
40672
+ calloutAssetResourceNames: { type: array, items: { type: string } }
40673
+ structuredSnippetAssetResourceNames: { type: array, items: { type: string } }
40674
+ '400': { description: "Invalid input, or Google rejected the assets" }
40675
+ '401': { $ref: '#/components/responses/Unauthorized' }
40676
+ '501': { description: Only supported on Google Ads }
40677
+
40511
40678
  /v1/ads/campaigns/{campaignId}/analytics:
40512
40679
  get:
40513
40680
  x-resource-group: "ads"
@@ -43349,6 +43516,39 @@ paths:
43349
43516
  linkUrl: { type: string, format: uri, description: "Final URL the sitelink navigates to." }
43350
43517
  description1: { type: string, minLength: 1, maxLength: 35, description: "First description line under the link text (optional). 35-char cap." }
43351
43518
  description2: { type: string, minLength: 1, maxLength: 35, description: "Second description line (optional; usually paired with description1)." }
43519
+ callouts:
43520
+ type: array
43521
+ minItems: 1
43522
+ maxItems: 20
43523
+ items: { type: string, minLength: 1, maxLength: 25 }
43524
+ description: |
43525
+ Google Search only. Short callout texts (max 25 chars each) that appear as
43526
+ non-clickable annotations under the ad, e.g. "Free shipping", "24/7 support".
43527
+ Each becomes one Asset (`callout_asset`) plus a CampaignAsset link with
43528
+ field_type CALLOUT. Response's creative.callouts[] echoes each input plus
43529
+ its Google resourceName.
43530
+ structuredSnippets:
43531
+ type: array
43532
+ minItems: 1
43533
+ maxItems: 20
43534
+ description: |
43535
+ Google Search only. Structured snippets — one header from Google's
43536
+ predefined list plus 3-10 values (max 25 chars each). Each becomes one
43537
+ Asset (`structured_snippet_asset`) plus a CampaignAsset link with
43538
+ field_type STRUCTURED_SNIPPET.
43539
+ items:
43540
+ type: object
43541
+ required: [header, values]
43542
+ properties:
43543
+ header:
43544
+ type: string
43545
+ enum: [Amenities, Brands, Courses, Degree programs, Destinations, Featured hotels, Insurance coverage, Models, Neighborhoods, Service catalog, Shows, Styles, Types]
43546
+ description: "One of Google's 13 predefined snippet headers."
43547
+ values:
43548
+ type: array
43549
+ minItems: 3
43550
+ maxItems: 10
43551
+ items: { type: string, minLength: 1, maxLength: 25 }
43352
43552
  advantageAudience: { type: integer, enum: [0, 1], description: "Meta only. Controls the Advantage audience feature (targeting_automation). 0 = disabled (default), 1 = enabled. Meta Marketing API requires this field on all ad set creation requests." }
43353
43553
  attributionSpec:
43354
43554
  type: array
@@ -32,6 +32,19 @@ describe 'AdCampaignsApi' do
32
32
  end
33
33
  end
34
34
 
35
+ # unit tests for attach_campaign_assets
36
+ # Attach extension assets to a Google Search campaign
37
+ # Attach sitelinks, callouts and/or structured snippets to an already-existing Google Search campaign — the same builders POST /v1/ads/create uses, but without rebuilding the hierarchy. At least one of sitelinks, callouts or structuredSnippets is required. Google-only. Other platforms have no equivalent extension surface and return 501. Approval status is Google-async; poll `asset.policy_summary` after review. Assets stay in the account library even if the campaign is later deleted.
38
+ # @param campaign_id Numeric Google platform campaign id.
39
+ # @param attach_campaign_assets_request
40
+ # @param [Hash] opts the optional parameters
41
+ # @return [AttachCampaignAssets201Response]
42
+ describe 'attach_campaign_assets test' do
43
+ it 'should work' do
44
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
45
+ end
46
+ end
47
+
35
48
  # unit tests for boost_post
36
49
  # Boost post as ad
37
50
  # Creates a paid ad from an existing published post, keeping the post's engagement. By default it provisions the whole hierarchy (campaign, ad set, ad). **Attach shape (Meta).** Send `adSetId` to put the ad under an EXISTING ad set instead, so that ad set keeps its learning phase. It then owns `budget`, `schedule` and `targeting`, and sending any of those alongside `adSetId` is a 400 rather than a silent drop. `budget` is required only without `adSetId`. `instagramAccountId`, `destinationType` and `adSetId` are Meta-only and return 400 on other platforms. **Retries.** Boosts are NOT idempotent and can take minutes when Meta requires re-hosting an Instagram video, so do not retry on client timeout. Send an Idempotency-Key header to make retries safe: same key and body replays the original 201, and distinct keys always create distinct ads. Without the header, an identical request is treated as a retry: while one is in flight it returns 409, and within 10 minutes of a completed boost it returns the already-created ad instead of creating another. To intentionally duplicate an ad, send distinct Idempotency-Keys (or vary the body, e.g. the name).
@@ -45,7 +45,7 @@ describe 'AnalyticsApi' do
45
45
  # @option opts [Date] :to_date Inclusive upper bound (YYYY-MM-DD). Defaults to today if omitted.
46
46
  # @option opts [Integer] :limit Page size (default 50)
47
47
  # @option opts [Integer] :page Page number (default 1)
48
- # @option opts [String] :sort_by Sort by date, engagement, or a specific metric
48
+ # @option opts [String] :sort_by Sort by date, engagement, or a specific metric. Instagram-only metrics (follows, reposts, reels_skip_rate, ig_reels_*) sort posts with no value as 0.
49
49
  # @option opts [String] :order Sort order
50
50
  # @return [GetAnalytics200Response]
51
51
  describe 'get_analytics test' do
@@ -48,7 +48,7 @@ describe 'MessagesApi' do
48
48
 
49
49
  # unit tests for create_inbox_conversation
50
50
  # Create conversation
51
- # Initiate a new direct message conversation with a specified user. If a conversation already exists with the recipient, the message is added to the existing thread. Supported platforms: X/Twitter, Bluesky, Reddit, WhatsApp, SMS, and Slack. Other platforms return PLATFORM_NOT_SUPPORTED. Slack: pass a workspace member id as participantId (list them with GET /v1/accounts/{accountId}/slack-members). Zernio opens the DM channel with that member and sends the message; the thread then behaves like any other Slack conversation in the inbox. The member must belong to the connected workspace. WhatsApp: this is the endpoint for sending an approved template message to a phone number. Provide templateName, templateLanguage, and templateParams (variable values for the text header, body and dynamic URL buttons, in that order), with the recipient phone in participantId. A template is required because WhatsApp does not permit freeform messages to open a conversation; a missing template returns TEMPLATE_REQUIRED. Templates with media headers (image, video, document) are handled automatically: Zernio reads the approved template definition and fills the header at send time with the template's approved sample asset. To send a DIFFERENT asset per message (e.g. a distinct invoice PDF for each recipient), pass the headerMedia field with a public link (or a Meta media id); it overrides the sample for that send. Calling this for a number you already have a thread with simply sends the template into that thread, which also makes it the way to re-engage a contact after the 24-hour customer-service window has closed. Once the recipient replies (opening the 24h window), send freeform messages with the send-message endpoint (POST /v1/inbox/conversations/{conversationId}/messages). Template fields are accepted on the JSON body only, not on multipart requests. Alternatively, WhatsApp Business Accounts eligible for Meta Direct Send can open a conversation with a business-initiated utility text message and no template: pass category: 'utility' together with message (and no templateName). See the category field below. DM eligibility (X/Twitter): Before sending, the endpoint checks if the recipient accepts DMs from your account (via the receives_your_dm field). If not, a 422 error with code DM_NOT_ALLOWED is returned. You can skip this check with skipDmCheck: true if you have already verified eligibility. X API tier requirement: DM write endpoints require X API Pro tier ($5,000/month) or Enterprise access. This applies to BYOK (Bring Your Own Key) users who provide their own X API credentials. Rate limits (X/Twitter only): X's DM API enforces 200 requests per 15 minutes, 1,000 per 24 hours per connected X account, and 15,000 per 24 hours per X developer app (shared across all DM endpoints). These limits do NOT apply to other platforms. WhatsApp sends are governed by Meta's per-number messaging tiers (unique business-initiated conversations per 24 hours) and per-number throughput instead.
51
+ # Initiate a new direct message conversation with a specified user. If a conversation already exists with the recipient, the message is added to the existing thread. Supported platforms: X/Twitter, Bluesky, Reddit, WhatsApp, SMS, and Slack. Other platforms return PLATFORM_NOT_SUPPORTED. Slack: pass a workspace member id as participantId (list them with GET /v1/accounts/{accountId}/slack-members). Zernio opens the DM channel with that member and sends the message; the thread then behaves like any other Slack conversation in the inbox. The member must belong to the connected workspace. WhatsApp: this is the endpoint for sending an approved template message to a phone number. Provide templateName, templateLanguage, and templateParams (variable values for the text header, body and dynamic URL buttons, in that order), with the recipient phone in participantId. A template is required because WhatsApp does not permit freeform messages to open a conversation; a missing template returns TEMPLATE_REQUIRED. Templates with media headers (image, video, document) are handled automatically: Zernio reads the approved template definition and fills the header at send time with the template's approved sample asset. To send a DIFFERENT asset per message (e.g. a distinct invoice PDF for each recipient), pass the headerMedia field with a public link (or a Meta media id); it overrides the sample for that send. A button that carries its own value at send time (a copy-code button holding a Pix payment code or a coupon, a flow token) is sent with templateButtonParams, addressed by the button's index; templateParams covers text variables and dynamic URL buttons only. Calling this for a number you already have a thread with simply sends the template into that thread, which also makes it the way to re-engage a contact after the 24-hour customer-service window has closed. Once the recipient replies (opening the 24h window), send freeform messages with the send-message endpoint (POST /v1/inbox/conversations/{conversationId}/messages). Template fields are accepted on the JSON body only, not on multipart requests. Alternatively, WhatsApp Business Accounts eligible for Meta Direct Send can open a conversation with a business-initiated utility text message and no template: pass category: 'utility' together with message (and no templateName). See the category field below. DM eligibility (X/Twitter): Before sending, the endpoint checks if the recipient accepts DMs from your account (via the receives_your_dm field). If not, a 422 error with code DM_NOT_ALLOWED is returned. You can skip this check with skipDmCheck: true if you have already verified eligibility. X API tier requirement: DM write endpoints require X API Pro tier ($5,000/month) or Enterprise access. This applies to BYOK (Bring Your Own Key) users who provide their own X API credentials. Rate limits (X/Twitter only): X's DM API enforces 200 requests per 15 minutes, 1,000 per 24 hours per connected X account, and 15,000 per 24 hours per X developer app (shared across all DM endpoints). These limits do NOT apply to other platforms. WhatsApp sends are governed by Meta's per-number messaging tiers (unique business-initiated conversations per 24 hours) and per-number throughput instead.
52
52
  # @param create_inbox_conversation_request
53
53
  # @param [Hash] opts the optional parameters
54
54
  # @return [CreateInboxConversation201Response]
@@ -0,0 +1,54 @@
1
+ =begin
2
+ #Zernio API
3
+
4
+ #API reference for Zernio. Authenticate with a Bearer API key. Base URL: https://zernio.com/api Versioning and deprecation: all endpoints are versioned in the URL path (current version: /v1). Breaking changes only ship in a new path version; existing versions keep working. Deprecated operations are marked 'deprecated: true' in this spec and announced in the changelog (https://zernio.com/changelog) before removal. Errors: every 4xx/5xx response is application/json with a machine-readable 'code' and a human-readable 'error' message (see the ErrorResponse schema).
5
+
6
+ The version of the OpenAPI document: 1.0.4
7
+ Contact: support@zernio.com
8
+ Generated by: https://openapi-generator.tech
9
+ Generator version: 7.19.0
10
+
11
+ =end
12
+
13
+ require 'spec_helper'
14
+ require 'json'
15
+ require 'date'
16
+
17
+ # Unit tests for Zernio::AttachCampaignAssets201Response
18
+ # Automatically generated by openapi-generator (https://openapi-generator.tech)
19
+ # Please update as you see appropriate
20
+ describe Zernio::AttachCampaignAssets201Response do
21
+ #let(:instance) { Zernio::AttachCampaignAssets201Response.new }
22
+
23
+ describe 'test an instance of AttachCampaignAssets201Response' do
24
+ it 'should create an instance of AttachCampaignAssets201Response' do
25
+ # uncomment below to test the instance creation
26
+ #expect(instance).to be_instance_of(Zernio::AttachCampaignAssets201Response)
27
+ end
28
+ end
29
+
30
+ describe 'test attribute "campaign_id"' do
31
+ it 'should work' do
32
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
33
+ end
34
+ end
35
+
36
+ describe 'test attribute "sitelink_asset_resource_names"' do
37
+ it 'should work' do
38
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
39
+ end
40
+ end
41
+
42
+ describe 'test attribute "callout_asset_resource_names"' do
43
+ it 'should work' do
44
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
45
+ end
46
+ end
47
+
48
+ describe 'test attribute "structured_snippet_asset_resource_names"' do
49
+ it 'should work' do
50
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
51
+ end
52
+ end
53
+
54
+ end
@@ -0,0 +1,54 @@
1
+ =begin
2
+ #Zernio API
3
+
4
+ #API reference for Zernio. Authenticate with a Bearer API key. Base URL: https://zernio.com/api Versioning and deprecation: all endpoints are versioned in the URL path (current version: /v1). Breaking changes only ship in a new path version; existing versions keep working. Deprecated operations are marked 'deprecated: true' in this spec and announced in the changelog (https://zernio.com/changelog) before removal. Errors: every 4xx/5xx response is application/json with a machine-readable 'code' and a human-readable 'error' message (see the ErrorResponse schema).
5
+
6
+ The version of the OpenAPI document: 1.0.4
7
+ Contact: support@zernio.com
8
+ Generated by: https://openapi-generator.tech
9
+ Generator version: 7.19.0
10
+
11
+ =end
12
+
13
+ require 'spec_helper'
14
+ require 'json'
15
+ require 'date'
16
+
17
+ # Unit tests for Zernio::AttachCampaignAssetsRequestSitelinksInner
18
+ # Automatically generated by openapi-generator (https://openapi-generator.tech)
19
+ # Please update as you see appropriate
20
+ describe Zernio::AttachCampaignAssetsRequestSitelinksInner do
21
+ #let(:instance) { Zernio::AttachCampaignAssetsRequestSitelinksInner.new }
22
+
23
+ describe 'test an instance of AttachCampaignAssetsRequestSitelinksInner' do
24
+ it 'should create an instance of AttachCampaignAssetsRequestSitelinksInner' do
25
+ # uncomment below to test the instance creation
26
+ #expect(instance).to be_instance_of(Zernio::AttachCampaignAssetsRequestSitelinksInner)
27
+ end
28
+ end
29
+
30
+ describe 'test attribute "text"' do
31
+ it 'should work' do
32
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
33
+ end
34
+ end
35
+
36
+ describe 'test attribute "link_url"' do
37
+ it 'should work' do
38
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
39
+ end
40
+ end
41
+
42
+ describe 'test attribute "description1"' do
43
+ it 'should work' do
44
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
45
+ end
46
+ end
47
+
48
+ describe 'test attribute "description2"' do
49
+ it 'should work' do
50
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
51
+ end
52
+ end
53
+
54
+ end
@@ -0,0 +1,54 @@
1
+ =begin
2
+ #Zernio API
3
+
4
+ #API reference for Zernio. Authenticate with a Bearer API key. Base URL: https://zernio.com/api Versioning and deprecation: all endpoints are versioned in the URL path (current version: /v1). Breaking changes only ship in a new path version; existing versions keep working. Deprecated operations are marked 'deprecated: true' in this spec and announced in the changelog (https://zernio.com/changelog) before removal. Errors: every 4xx/5xx response is application/json with a machine-readable 'code' and a human-readable 'error' message (see the ErrorResponse schema).
5
+
6
+ The version of the OpenAPI document: 1.0.4
7
+ Contact: support@zernio.com
8
+ Generated by: https://openapi-generator.tech
9
+ Generator version: 7.19.0
10
+
11
+ =end
12
+
13
+ require 'spec_helper'
14
+ require 'json'
15
+ require 'date'
16
+
17
+ # Unit tests for Zernio::AttachCampaignAssetsRequest
18
+ # Automatically generated by openapi-generator (https://openapi-generator.tech)
19
+ # Please update as you see appropriate
20
+ describe Zernio::AttachCampaignAssetsRequest do
21
+ #let(:instance) { Zernio::AttachCampaignAssetsRequest.new }
22
+
23
+ describe 'test an instance of AttachCampaignAssetsRequest' do
24
+ it 'should create an instance of AttachCampaignAssetsRequest' do
25
+ # uncomment below to test the instance creation
26
+ #expect(instance).to be_instance_of(Zernio::AttachCampaignAssetsRequest)
27
+ end
28
+ end
29
+
30
+ describe 'test attribute "account_id"' do
31
+ it 'should work' do
32
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
33
+ end
34
+ end
35
+
36
+ describe 'test attribute "sitelinks"' do
37
+ it 'should work' do
38
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
39
+ end
40
+ end
41
+
42
+ describe 'test attribute "callouts"' do
43
+ it 'should work' do
44
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
45
+ end
46
+ end
47
+
48
+ describe 'test attribute "structured_snippets"' do
49
+ it 'should work' do
50
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
51
+ end
52
+ end
53
+
54
+ end
@@ -0,0 +1,46 @@
1
+ =begin
2
+ #Zernio API
3
+
4
+ #API reference for Zernio. Authenticate with a Bearer API key. Base URL: https://zernio.com/api Versioning and deprecation: all endpoints are versioned in the URL path (current version: /v1). Breaking changes only ship in a new path version; existing versions keep working. Deprecated operations are marked 'deprecated: true' in this spec and announced in the changelog (https://zernio.com/changelog) before removal. Errors: every 4xx/5xx response is application/json with a machine-readable 'code' and a human-readable 'error' message (see the ErrorResponse schema).
5
+
6
+ The version of the OpenAPI document: 1.0.4
7
+ Contact: support@zernio.com
8
+ Generated by: https://openapi-generator.tech
9
+ Generator version: 7.19.0
10
+
11
+ =end
12
+
13
+ require 'spec_helper'
14
+ require 'json'
15
+ require 'date'
16
+
17
+ # Unit tests for Zernio::AttachCampaignAssetsRequestStructuredSnippetsInner
18
+ # Automatically generated by openapi-generator (https://openapi-generator.tech)
19
+ # Please update as you see appropriate
20
+ describe Zernio::AttachCampaignAssetsRequestStructuredSnippetsInner do
21
+ #let(:instance) { Zernio::AttachCampaignAssetsRequestStructuredSnippetsInner.new }
22
+
23
+ describe 'test an instance of AttachCampaignAssetsRequestStructuredSnippetsInner' do
24
+ it 'should create an instance of AttachCampaignAssetsRequestStructuredSnippetsInner' do
25
+ # uncomment below to test the instance creation
26
+ #expect(instance).to be_instance_of(Zernio::AttachCampaignAssetsRequestStructuredSnippetsInner)
27
+ end
28
+ end
29
+
30
+ describe 'test attribute "header"' do
31
+ it 'should work' do
32
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
33
+ # validator = Petstore::EnumTest::EnumAttributeValidator.new('String', ["Amenities", "Brands", "Courses", "Degree programs", "Destinations", "Featured hotels", "Insurance coverage", "Models", "Neighborhoods", "Service catalog", "Shows", "Styles", "Types"])
34
+ # validator.allowable_values.each do |value|
35
+ # expect { instance.header = value }.not_to raise_error
36
+ # end
37
+ end
38
+ end
39
+
40
+ describe 'test attribute "values"' do
41
+ it 'should work' do
42
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
43
+ end
44
+ end
45
+
46
+ end
@@ -91,6 +91,12 @@ describe Zernio::CreateInboxConversationRequest do
91
91
  end
92
92
  end
93
93
 
94
+ describe 'test attribute "template_button_params"' do
95
+ it 'should work' do
96
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
97
+ end
98
+ end
99
+
94
100
  describe 'test attribute "header_media"' do
95
101
  it 'should work' do
96
102
  # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/