zernio-sdk 0.0.916 → 0.0.918

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 (26) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -0
  3. data/docs/AdCampaignsApi.md +1 -1
  4. data/docs/CreateInboxConversationRequest.md +2 -0
  5. data/docs/CreateInboxConversationRequestTemplateCardsInner.md +24 -0
  6. data/docs/CreateInboxConversationRequestTemplateCardsInnerButtonsInner.md +22 -0
  7. data/docs/CreateInboxConversationRequestTemplateCardsInnerHeaderMedia.md +22 -0
  8. data/docs/MessagesApi.md +1 -1
  9. data/lib/zernio-sdk/api/ad_campaigns_api.rb +2 -2
  10. data/lib/zernio-sdk/api/messages_api.rb +2 -2
  11. data/lib/zernio-sdk/models/create_inbox_conversation400_response.rb +2 -2
  12. data/lib/zernio-sdk/models/create_inbox_conversation_request.rb +32 -1
  13. data/lib/zernio-sdk/models/create_inbox_conversation_request_template_cards_inner.rb +235 -0
  14. data/lib/zernio-sdk/models/create_inbox_conversation_request_template_cards_inner_buttons_inner.rb +270 -0
  15. data/lib/zernio-sdk/models/create_inbox_conversation_request_template_cards_inner_header_media.rb +210 -0
  16. data/lib/zernio-sdk/version.rb +1 -1
  17. data/lib/zernio-sdk.rb +3 -0
  18. data/openapi.yaml +63 -2
  19. data/spec/api/ad_campaigns_api_spec.rb +1 -1
  20. data/spec/api/messages_api_spec.rb +1 -1
  21. data/spec/models/create_inbox_conversation400_response_spec.rb +1 -1
  22. data/spec/models/create_inbox_conversation_request_spec.rb +6 -0
  23. data/spec/models/create_inbox_conversation_request_template_cards_inner_buttons_inner_spec.rb +52 -0
  24. data/spec/models/create_inbox_conversation_request_template_cards_inner_header_media_spec.rb +52 -0
  25. data/spec/models/create_inbox_conversation_request_template_cards_inner_spec.rb +54 -0
  26. metadata +13 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0a7b0af6d729b07ecce3f1dd1eddc4bc98f8f2841d29771bb6284f3507fc7ae9
4
- data.tar.gz: f31336c454922b6a0afa846ee3b41bbf88dbaaced5aed61fb45b2ce8eadaa6a8
3
+ metadata.gz: 164d76ec4381802e8098926f92a00a06ef28e344bd6555b772aff2d8c062e75c
4
+ data.tar.gz: fff6c8a338864897de5b5637d7dbb59126c4b62f7951e48f601fd16512f15f03
5
5
  SHA512:
6
- metadata.gz: 0f873866020d099f8f8e2f7cb9be01a19d3cbcb274c27a7de0599324ba269dc97260721d0cb0d41be9e6e987bcb49ab96d93c5833f25e928d98683e96e5e310a
7
- data.tar.gz: 1b9115180ea258ebcb5221b262df0a24d233801f11b80b326f24559fd872b136ec34b3167f5e6aa0648c10f7917470946343a5b2ceb623a0ef88335e2ff13db1
6
+ metadata.gz: 107e8614dc148266e07bae612047dce1ecee7f1781628416b3d155883eaba18e51c9d4bc244d877d402ef1e059995c1df165d5c6f4ff5f489dc1e3723cb85fb7
7
+ data.tar.gz: 0dde1eea3e8236a1a0b17893f23af2076f90c91109b2249133c3e14182cc9dea7349f7515ab9e601f4ef14ebe5d2eed025c7711d2ef910199a705b5ef7cacad4
data/README.md CHANGED
@@ -1120,6 +1120,9 @@ Class | Method | HTTP request | Description
1120
1120
  - [Zernio::CreateInboxConversationRequestHeaderLocation](docs/CreateInboxConversationRequestHeaderLocation.md)
1121
1121
  - [Zernio::CreateInboxConversationRequestHeaderMedia](docs/CreateInboxConversationRequestHeaderMedia.md)
1122
1122
  - [Zernio::CreateInboxConversationRequestTemplateButtonParamsInner](docs/CreateInboxConversationRequestTemplateButtonParamsInner.md)
1123
+ - [Zernio::CreateInboxConversationRequestTemplateCardsInner](docs/CreateInboxConversationRequestTemplateCardsInner.md)
1124
+ - [Zernio::CreateInboxConversationRequestTemplateCardsInnerButtonsInner](docs/CreateInboxConversationRequestTemplateCardsInnerButtonsInner.md)
1125
+ - [Zernio::CreateInboxConversationRequestTemplateCardsInnerHeaderMedia](docs/CreateInboxConversationRequestTemplateCardsInnerHeaderMedia.md)
1123
1126
  - [Zernio::CreateInviteToken201Response](docs/CreateInviteToken201Response.md)
1124
1127
  - [Zernio::CreateInviteTokenRequest](docs/CreateInviteTokenRequest.md)
1125
1128
  - [Zernio::CreateLeadForm200Response](docs/CreateLeadForm200Response.md)
@@ -627,7 +627,7 @@ end
627
627
 
628
628
  Create standalone ad
629
629
 
630
- Create a paid ad with custom creative across Meta, Google Ads, Pinterest, TikTok, X, LinkedIn, and OpenAI Ads (ChatGPT Ads). Google Performance Max: set `campaignType: \"pmax\"` and supply `assetGroup` with text, images by role, business name and finalUrl. Creates a daily budget, PAUSED campaign and asset group atomically. `validateOnly: true` validates the complete request with Google without creating or persisting resources. Read assets with `GET /v1/ads/campaigns/{campaignId}/asset-groups`. The logo is required; video is optional via `assetGroup.youtubeVideoId`. Brand guidelines are disabled at creation. PMax rejects ACTIVE creation, portfolio bidding, bid caps, legacy creative fields and attach shapes. Geo and language targeting are supported; omitted geo targets all locations. PMax does not require top-level goal, headline, body or linkUrl. Supported bidding: omitted or LOWEST_COST_WITHOUT_CAP for Maximize Conversions, COST_CAP plus bidAmount for target CPA, LOWEST_COST_WITH_MIN_ROAS plus roasAverageFloor for Maximize Conversion Value with target ROAS. Other mutually-exclusive request shapes are selected by the body: - Legacy single-creative shape (all platforms, the default). - Meta-only multi-creative shape via the creatives array: one ad set with N ads sharing budget and targeting. - Attach shape via adSetId: adds one new ad to an existing ad set, inheriting its budget, targeting, and schedule (Meta, Google Ads, TikTok, and LinkedIn). On LinkedIn adSetId is the existing Campaign id, and the budget, schedule, targeting and bidding fields must be omitted. Meta accepts `promotion` and `creativeFeatures` on the single and attach shapes and as defaults for `creatives[]`. An item replaces the whole feature map; its `promotion` replaces the default offer, and `promotion: null` disables that default for the item. Reusing `existingCreativeId` uses the existing creative settings instead of new settings. Requested settings are persisted for lists, exports, and default ad-detail reads. Only ads supplied a `promotion` receive live readback; multi-create batches those reads in groups of up to 50 IDs without per-ad fallback. Inspect `ad.creative.promotionStatus` (or `ads[].creative.promotionStatus`). `not_returned` means Meta omitted the metadata; successful creation does not by itself prove the offer was applied or will display. Per-platform required fields, budget minimums, and video-ad rules are documented on each property below. LinkedIn creates a Single Image or Single Video Ad backed by a Direct Sponsored Content \"dark post\" authored by a Company Page (see `organizationId`). Supported goals are engagement, traffic, awareness, and video_views (video ads use the `video` field; video_views requires a video), and traffic ads require `linkUrl`. **Idempotency:** this endpoint is not idempotent at the platform level (a blind retry creates a second campaign/ad set/ad). Send an `Idempotency-Key` header to make retries safe: the first request with a given key creates the ad and we store the response; a retry with the same key replays that exact response (with `Idempotent-Replayed: true`) instead of creating duplicates. Reusing a key with a different body returns 422; a key whose first request is still in flight returns 409 (retry after a short backoff). Keys are scoped to your credential and expire after 24h.
630
+ Create a paid ad with custom creative across Meta, Google Ads, Pinterest, TikTok, X, LinkedIn, and OpenAI Ads (ChatGPT Ads). Google Performance Max: set `campaignType: \"pmax\"` and supply `assetGroup` with text, images by role, business name and finalUrl. Creates a daily budget, PAUSED campaign and asset group atomically. `validateOnly: true` validates the complete request with Google without creating or persisting resources. Read assets with `GET /v1/ads/campaigns/{campaignId}/asset-groups`. The logo is required; video is optional via `assetGroup.youtubeVideoId`. Brand guidelines are disabled at creation. All supplied asset links are validated together against Google's minimum asset requirements. PMax rejects ACTIVE creation, portfolio bidding, bid caps, legacy creative fields and attach shapes. Geo and language targeting are supported; omitted geo targets all locations. PMax does not require top-level goal, headline, body or linkUrl. Supported bidding: omitted or LOWEST_COST_WITHOUT_CAP for Maximize Conversions, COST_CAP plus bidAmount for target CPA, LOWEST_COST_WITH_MIN_ROAS plus roasAverageFloor for Maximize Conversion Value with target ROAS. Other mutually-exclusive request shapes are selected by the body: - Legacy single-creative shape (all platforms, the default). - Meta-only multi-creative shape via the creatives array: one ad set with N ads sharing budget and targeting. - Attach shape via adSetId: adds one new ad to an existing ad set, inheriting its budget, targeting, and schedule (Meta, Google Ads, TikTok, and LinkedIn). On LinkedIn adSetId is the existing Campaign id, and the budget, schedule, targeting and bidding fields must be omitted. Meta accepts `promotion` and `creativeFeatures` on the single and attach shapes and as defaults for `creatives[]`. An item replaces the whole feature map; its `promotion` replaces the default offer, and `promotion: null` disables that default for the item. Reusing `existingCreativeId` uses the existing creative settings instead of new settings. Requested settings are persisted for lists, exports, and default ad-detail reads. Only ads supplied a `promotion` receive live readback; multi-create batches those reads in groups of up to 50 IDs without per-ad fallback. Inspect `ad.creative.promotionStatus` (or `ads[].creative.promotionStatus`). `not_returned` means Meta omitted the metadata; successful creation does not by itself prove the offer was applied or will display. Per-platform required fields, budget minimums, and video-ad rules are documented on each property below. LinkedIn creates a Single Image or Single Video Ad backed by a Direct Sponsored Content \"dark post\" authored by a Company Page (see `organizationId`). Supported goals are engagement, traffic, awareness, and video_views (video ads use the `video` field; video_views requires a video), and traffic ads require `linkUrl`. **Idempotency:** this endpoint is not idempotent at the platform level (a blind retry creates a second campaign/ad set/ad). Send an `Idempotency-Key` header to make retries safe: the first request with a given key creates the ad and we store the response; a retry with the same key replays that exact response (with `Idempotent-Replayed: true`) instead of creating duplicates. Reusing a key with a different body returns 422; a key whose first request is still in flight returns 409 (retry after a short backoff). Keys are scoped to your credential and expire after 24h.
631
631
 
632
632
  ### Examples
633
633
 
@@ -15,6 +15,7 @@
15
15
  | **template_language** | **String** | WhatsApp only. Template language code (e.g. en_US). | [optional] |
16
16
  | **template_params** | **Array<String>** | WhatsApp only. Template variable values as one flat array, in the order the variables appear across the whole template: text-header variables first, then body variables, then one value per dynamic URL button (in button order). Works with positional placeholders ({{1}}, {{2}}, ...) and with named placeholders ({{name}}, {{company}} - how Meta Business Manager creates templates), where values fill the named slots in order of appearance. Example - a body with {{1}}, {{2}} plus a URL button https://example.com/{{1}} takes three values: [body1, body2, buttonSuffix]. For positional templates the list must cover every slot: supplying fewer values than the template's header + body + dynamic URL-button count is rejected with a 400 (code INVALID_TEMPLATE_PARAMS) naming the expected split, rather than delivering a template whose button URL was filled from the wrong value. A dynamic URL button covered by templateButtonParams needs no value here unless another uncovered dynamic URL button follows it, since the override applies after slot numbering. Media headers (image, video, document) are filled automatically from the approved template and take no value here (use headerMedia to override the header asset per send). Buttons that are not dynamic-URL buttons (copy-code, flow) take no value here either; use templateButtonParams. | [optional] |
17
17
  | **template_button_params** | [**Array<CreateInboxConversationRequestTemplateButtonParamsInner>**](CreateInboxConversationRequestTemplateButtonParamsInner.md) | WhatsApp only. Values for template buttons that carry one at send time, each addressed by the button's position in the approved template. This is the only way to send a copy-code button's payload (a Pix payment code, a coupon) or a flow token, because templateParams is a flat array of text variables and covers dynamic URL buttons only. Supplying a button here overrides whatever templateParams would have derived for that same index, so the send never carries one button twice; repeating an index within this array is rejected with 400. Each index must name a button of the matching kind on the approved template, which is also checked before the send and returns 400 (INVALID_TEMPLATE_BUTTON_PARAM) rather than a Meta rejection. | [optional] |
18
+ | **template_cards** | [**Array<CreateInboxConversationRequestTemplateCardsInner>**](CreateInboxConversationRequestTemplateCardsInner.md) | WhatsApp only. Per-card overrides for a CAROUSEL template, each addressed by the card's card_index. Carousel card body variables restart at {{1}} per card, so they cannot be expressed in the flat templateParams slot order; use this instead. A cardIndex naming a card the approved template does not have, a duplicate cardIndex, or a params count that does not match the card body's token count is rejected with 400 (INVALID_TEMPLATE_CARD_PARAM). | [optional] |
18
19
  | **header_media** | [**CreateInboxConversationRequestHeaderMedia**](CreateInboxConversationRequestHeaderMedia.md) | | [optional] |
19
20
  | **header_location** | [**CreateInboxConversationRequestHeaderLocation**](CreateInboxConversationRequestHeaderLocation.md) | | [optional] |
20
21
 
@@ -35,6 +36,7 @@ instance = Zernio::CreateInboxConversationRequest.new(
35
36
  template_language: null,
36
37
  template_params: null,
37
38
  template_button_params: null,
39
+ template_cards: null,
38
40
  header_media: null,
39
41
  header_location: null
40
42
  )
@@ -0,0 +1,24 @@
1
+ # Zernio::CreateInboxConversationRequestTemplateCardsInner
2
+
3
+ ## Properties
4
+
5
+ | Name | Type | Description | Notes |
6
+ | ---- | ---- | ----------- | ----- |
7
+ | **card_index** | **Integer** | The card's card_index in the approved template. | |
8
+ | **params** | **Array<String>** | Values for this card's own body variables, in the card's own {{1}}, {{2}}, ... order (or named-slot order of appearance). | [optional] |
9
+ | **header_media** | [**CreateInboxConversationRequestTemplateCardsInnerHeaderMedia**](CreateInboxConversationRequestTemplateCardsInnerHeaderMedia.md) | | [optional] |
10
+ | **buttons** | [**Array<CreateInboxConversationRequestTemplateCardsInnerButtonsInner>**](CreateInboxConversationRequestTemplateCardsInnerButtonsInner.md) | Values for this card's own buttons, each addressed by the button's index within the card. | [optional] |
11
+
12
+ ## Example
13
+
14
+ ```ruby
15
+ require 'zernio-sdk'
16
+
17
+ instance = Zernio::CreateInboxConversationRequestTemplateCardsInner.new(
18
+ card_index: null,
19
+ params: null,
20
+ header_media: null,
21
+ buttons: null
22
+ )
23
+ ```
24
+
@@ -0,0 +1,22 @@
1
+ # Zernio::CreateInboxConversationRequestTemplateCardsInnerButtonsInner
2
+
3
+ ## Properties
4
+
5
+ | Name | Type | Description | Notes |
6
+ | ---- | ---- | ----------- | ----- |
7
+ | **index** | **Integer** | Zero-based position of the button within the card's buttons. | |
8
+ | **sub_type** | **String** | The button kind, which decides how the value is sent. | |
9
+ | **value** | **String** | The value to send (quick_reply payload, or the URL dynamic suffix). | |
10
+
11
+ ## Example
12
+
13
+ ```ruby
14
+ require 'zernio-sdk'
15
+
16
+ instance = Zernio::CreateInboxConversationRequestTemplateCardsInnerButtonsInner.new(
17
+ index: null,
18
+ sub_type: null,
19
+ value: null
20
+ )
21
+ ```
22
+
@@ -0,0 +1,22 @@
1
+ # Zernio::CreateInboxConversationRequestTemplateCardsInnerHeaderMedia
2
+
3
+ ## Properties
4
+
5
+ | Name | Type | Description | Notes |
6
+ | ---- | ---- | ----------- | ----- |
7
+ | **type** | **String** | Must match the card header's media type. | |
8
+ | **link** | **String** | Public URL of the asset to send. Must be reachable without auth. | [optional] |
9
+ | **id** | **String** | A Meta media id (from the media upload endpoint), as an alternative to link. | [optional] |
10
+
11
+ ## Example
12
+
13
+ ```ruby
14
+ require 'zernio-sdk'
15
+
16
+ instance = Zernio::CreateInboxConversationRequestTemplateCardsInnerHeaderMedia.new(
17
+ type: null,
18
+ link: null,
19
+ id: null
20
+ )
21
+ ```
22
+
data/docs/MessagesApi.md CHANGED
@@ -101,7 +101,7 @@ end
101
101
 
102
102
  Create conversation
103
103
 
104
- Start a direct message conversation with a user. If a conversation with that recipient already exists, the message is added to the existing thread. Supported platforms: X, 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 template whose approved header format is LOCATION has no header asset to reconstruct at all: Meta only accepts the location at send time, so pass headerLocation (latitude and longitude required) whenever such a template is sent; headerMedia and headerLocation cannot both be supplied. - 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. - Template fields are accepted on the JSON body only, not on multipart requests. For a number you already have a thread with, this 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). 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).** 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 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.
104
+ Start a direct message conversation with a user. If a conversation with that recipient already exists, the message is added to the existing thread. Supported platforms: X, 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 template whose approved header format is LOCATION has no header asset to reconstruct at all: Meta only accepts the location at send time, so pass headerLocation (latitude and longitude required) whenever such a template is sent; headerMedia and headerLocation cannot both be supplied. - 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. - CAROUSEL templates take per-card overrides via templateCards, each addressed by the card's card_index, because card body variables restart at {{1}} per card and cannot be expressed in the flat templateParams order. - Template fields are accepted on the JSON body only, not on multipart requests. For a number you already have a thread with, this 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). 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).** 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 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.
105
105
 
106
106
  ### Examples
107
107
 
@@ -607,7 +607,7 @@ module Zernio
607
607
  end
608
608
 
609
609
  # Create standalone ad
610
- # Create a paid ad with custom creative across Meta, Google Ads, Pinterest, TikTok, X, LinkedIn, and OpenAI Ads (ChatGPT Ads). Google Performance Max: set `campaignType: \"pmax\"` and supply `assetGroup` with text, images by role, business name and finalUrl. Creates a daily budget, PAUSED campaign and asset group atomically. `validateOnly: true` validates the complete request with Google without creating or persisting resources. Read assets with `GET /v1/ads/campaigns/{campaignId}/asset-groups`. The logo is required; video is optional via `assetGroup.youtubeVideoId`. Brand guidelines are disabled at creation. PMax rejects ACTIVE creation, portfolio bidding, bid caps, legacy creative fields and attach shapes. Geo and language targeting are supported; omitted geo targets all locations. PMax does not require top-level goal, headline, body or linkUrl. Supported bidding: omitted or LOWEST_COST_WITHOUT_CAP for Maximize Conversions, COST_CAP plus bidAmount for target CPA, LOWEST_COST_WITH_MIN_ROAS plus roasAverageFloor for Maximize Conversion Value with target ROAS. Other mutually-exclusive request shapes are selected by the body: - Legacy single-creative shape (all platforms, the default). - Meta-only multi-creative shape via the creatives array: one ad set with N ads sharing budget and targeting. - Attach shape via adSetId: adds one new ad to an existing ad set, inheriting its budget, targeting, and schedule (Meta, Google Ads, TikTok, and LinkedIn). On LinkedIn adSetId is the existing Campaign id, and the budget, schedule, targeting and bidding fields must be omitted. Meta accepts `promotion` and `creativeFeatures` on the single and attach shapes and as defaults for `creatives[]`. An item replaces the whole feature map; its `promotion` replaces the default offer, and `promotion: null` disables that default for the item. Reusing `existingCreativeId` uses the existing creative settings instead of new settings. Requested settings are persisted for lists, exports, and default ad-detail reads. Only ads supplied a `promotion` receive live readback; multi-create batches those reads in groups of up to 50 IDs without per-ad fallback. Inspect `ad.creative.promotionStatus` (or `ads[].creative.promotionStatus`). `not_returned` means Meta omitted the metadata; successful creation does not by itself prove the offer was applied or will display. Per-platform required fields, budget minimums, and video-ad rules are documented on each property below. LinkedIn creates a Single Image or Single Video Ad backed by a Direct Sponsored Content \"dark post\" authored by a Company Page (see `organizationId`). Supported goals are engagement, traffic, awareness, and video_views (video ads use the `video` field; video_views requires a video), and traffic ads require `linkUrl`. **Idempotency:** this endpoint is not idempotent at the platform level (a blind retry creates a second campaign/ad set/ad). Send an `Idempotency-Key` header to make retries safe: the first request with a given key creates the ad and we store the response; a retry with the same key replays that exact response (with `Idempotent-Replayed: true`) instead of creating duplicates. Reusing a key with a different body returns 422; a key whose first request is still in flight returns 409 (retry after a short backoff). Keys are scoped to your credential and expire after 24h.
610
+ # Create a paid ad with custom creative across Meta, Google Ads, Pinterest, TikTok, X, LinkedIn, and OpenAI Ads (ChatGPT Ads). Google Performance Max: set `campaignType: \"pmax\"` and supply `assetGroup` with text, images by role, business name and finalUrl. Creates a daily budget, PAUSED campaign and asset group atomically. `validateOnly: true` validates the complete request with Google without creating or persisting resources. Read assets with `GET /v1/ads/campaigns/{campaignId}/asset-groups`. The logo is required; video is optional via `assetGroup.youtubeVideoId`. Brand guidelines are disabled at creation. All supplied asset links are validated together against Google's minimum asset requirements. PMax rejects ACTIVE creation, portfolio bidding, bid caps, legacy creative fields and attach shapes. Geo and language targeting are supported; omitted geo targets all locations. PMax does not require top-level goal, headline, body or linkUrl. Supported bidding: omitted or LOWEST_COST_WITHOUT_CAP for Maximize Conversions, COST_CAP plus bidAmount for target CPA, LOWEST_COST_WITH_MIN_ROAS plus roasAverageFloor for Maximize Conversion Value with target ROAS. Other mutually-exclusive request shapes are selected by the body: - Legacy single-creative shape (all platforms, the default). - Meta-only multi-creative shape via the creatives array: one ad set with N ads sharing budget and targeting. - Attach shape via adSetId: adds one new ad to an existing ad set, inheriting its budget, targeting, and schedule (Meta, Google Ads, TikTok, and LinkedIn). On LinkedIn adSetId is the existing Campaign id, and the budget, schedule, targeting and bidding fields must be omitted. Meta accepts `promotion` and `creativeFeatures` on the single and attach shapes and as defaults for `creatives[]`. An item replaces the whole feature map; its `promotion` replaces the default offer, and `promotion: null` disables that default for the item. Reusing `existingCreativeId` uses the existing creative settings instead of new settings. Requested settings are persisted for lists, exports, and default ad-detail reads. Only ads supplied a `promotion` receive live readback; multi-create batches those reads in groups of up to 50 IDs without per-ad fallback. Inspect `ad.creative.promotionStatus` (or `ads[].creative.promotionStatus`). `not_returned` means Meta omitted the metadata; successful creation does not by itself prove the offer was applied or will display. Per-platform required fields, budget minimums, and video-ad rules are documented on each property below. LinkedIn creates a Single Image or Single Video Ad backed by a Direct Sponsored Content \"dark post\" authored by a Company Page (see `organizationId`). Supported goals are engagement, traffic, awareness, and video_views (video ads use the `video` field; video_views requires a video), and traffic ads require `linkUrl`. **Idempotency:** this endpoint is not idempotent at the platform level (a blind retry creates a second campaign/ad set/ad). Send an `Idempotency-Key` header to make retries safe: the first request with a given key creates the ad and we store the response; a retry with the same key replays that exact response (with `Idempotent-Replayed: true`) instead of creating duplicates. Reusing a key with a different body returns 422; a key whose first request is still in flight returns 409 (retry after a short backoff). Keys are scoped to your credential and expire after 24h.
611
611
  # @param create_standalone_ad_request [CreateStandaloneAdRequest]
612
612
  # @param [Hash] opts the optional parameters
613
613
  # @option opts [String] :idempotency_key Optional client-generated unique key (e.g. a UUID) that makes retries safe. Same key + same body replays the original response; same key + different body → 422; key still processing → 409.
@@ -618,7 +618,7 @@ module Zernio
618
618
  end
619
619
 
620
620
  # Create standalone ad
621
- # Create a paid ad with custom creative across Meta, Google Ads, Pinterest, TikTok, X, LinkedIn, and OpenAI Ads (ChatGPT Ads). Google Performance Max: set `campaignType: \"pmax\"` and supply `assetGroup` with text, images by role, business name and finalUrl. Creates a daily budget, PAUSED campaign and asset group atomically. `validateOnly: true` validates the complete request with Google without creating or persisting resources. Read assets with `GET /v1/ads/campaigns/{campaignId}/asset-groups`. The logo is required; video is optional via `assetGroup.youtubeVideoId`. Brand guidelines are disabled at creation. PMax rejects ACTIVE creation, portfolio bidding, bid caps, legacy creative fields and attach shapes. Geo and language targeting are supported; omitted geo targets all locations. PMax does not require top-level goal, headline, body or linkUrl. Supported bidding: omitted or LOWEST_COST_WITHOUT_CAP for Maximize Conversions, COST_CAP plus bidAmount for target CPA, LOWEST_COST_WITH_MIN_ROAS plus roasAverageFloor for Maximize Conversion Value with target ROAS. Other mutually-exclusive request shapes are selected by the body: - Legacy single-creative shape (all platforms, the default). - Meta-only multi-creative shape via the creatives array: one ad set with N ads sharing budget and targeting. - Attach shape via adSetId: adds one new ad to an existing ad set, inheriting its budget, targeting, and schedule (Meta, Google Ads, TikTok, and LinkedIn). On LinkedIn adSetId is the existing Campaign id, and the budget, schedule, targeting and bidding fields must be omitted. Meta accepts `promotion` and `creativeFeatures` on the single and attach shapes and as defaults for `creatives[]`. An item replaces the whole feature map; its `promotion` replaces the default offer, and `promotion: null` disables that default for the item. Reusing `existingCreativeId` uses the existing creative settings instead of new settings. Requested settings are persisted for lists, exports, and default ad-detail reads. Only ads supplied a `promotion` receive live readback; multi-create batches those reads in groups of up to 50 IDs without per-ad fallback. Inspect `ad.creative.promotionStatus` (or `ads[].creative.promotionStatus`). `not_returned` means Meta omitted the metadata; successful creation does not by itself prove the offer was applied or will display. Per-platform required fields, budget minimums, and video-ad rules are documented on each property below. LinkedIn creates a Single Image or Single Video Ad backed by a Direct Sponsored Content \"dark post\" authored by a Company Page (see `organizationId`). Supported goals are engagement, traffic, awareness, and video_views (video ads use the `video` field; video_views requires a video), and traffic ads require `linkUrl`. **Idempotency:** this endpoint is not idempotent at the platform level (a blind retry creates a second campaign/ad set/ad). Send an `Idempotency-Key` header to make retries safe: the first request with a given key creates the ad and we store the response; a retry with the same key replays that exact response (with `Idempotent-Replayed: true`) instead of creating duplicates. Reusing a key with a different body returns 422; a key whose first request is still in flight returns 409 (retry after a short backoff). Keys are scoped to your credential and expire after 24h.
621
+ # Create a paid ad with custom creative across Meta, Google Ads, Pinterest, TikTok, X, LinkedIn, and OpenAI Ads (ChatGPT Ads). Google Performance Max: set `campaignType: \"pmax\"` and supply `assetGroup` with text, images by role, business name and finalUrl. Creates a daily budget, PAUSED campaign and asset group atomically. `validateOnly: true` validates the complete request with Google without creating or persisting resources. Read assets with `GET /v1/ads/campaigns/{campaignId}/asset-groups`. The logo is required; video is optional via `assetGroup.youtubeVideoId`. Brand guidelines are disabled at creation. All supplied asset links are validated together against Google's minimum asset requirements. PMax rejects ACTIVE creation, portfolio bidding, bid caps, legacy creative fields and attach shapes. Geo and language targeting are supported; omitted geo targets all locations. PMax does not require top-level goal, headline, body or linkUrl. Supported bidding: omitted or LOWEST_COST_WITHOUT_CAP for Maximize Conversions, COST_CAP plus bidAmount for target CPA, LOWEST_COST_WITH_MIN_ROAS plus roasAverageFloor for Maximize Conversion Value with target ROAS. Other mutually-exclusive request shapes are selected by the body: - Legacy single-creative shape (all platforms, the default). - Meta-only multi-creative shape via the creatives array: one ad set with N ads sharing budget and targeting. - Attach shape via adSetId: adds one new ad to an existing ad set, inheriting its budget, targeting, and schedule (Meta, Google Ads, TikTok, and LinkedIn). On LinkedIn adSetId is the existing Campaign id, and the budget, schedule, targeting and bidding fields must be omitted. Meta accepts `promotion` and `creativeFeatures` on the single and attach shapes and as defaults for `creatives[]`. An item replaces the whole feature map; its `promotion` replaces the default offer, and `promotion: null` disables that default for the item. Reusing `existingCreativeId` uses the existing creative settings instead of new settings. Requested settings are persisted for lists, exports, and default ad-detail reads. Only ads supplied a `promotion` receive live readback; multi-create batches those reads in groups of up to 50 IDs without per-ad fallback. Inspect `ad.creative.promotionStatus` (or `ads[].creative.promotionStatus`). `not_returned` means Meta omitted the metadata; successful creation does not by itself prove the offer was applied or will display. Per-platform required fields, budget minimums, and video-ad rules are documented on each property below. LinkedIn creates a Single Image or Single Video Ad backed by a Direct Sponsored Content \"dark post\" authored by a Company Page (see `organizationId`). Supported goals are engagement, traffic, awareness, and video_views (video ads use the `video` field; video_views requires a video), and traffic ads require `linkUrl`. **Idempotency:** this endpoint is not idempotent at the platform level (a blind retry creates a second campaign/ad set/ad). Send an `Idempotency-Key` header to make retries safe: the first request with a given key creates the ad and we store the response; a retry with the same key replays that exact response (with `Idempotent-Replayed: true`) instead of creating duplicates. Reusing a key with a different body returns 422; a key whose first request is still in flight returns 409 (retry after a short backoff). Keys are scoped to your credential and expire after 24h.
622
622
  # @param create_standalone_ad_request [CreateStandaloneAdRequest]
623
623
  # @param [Hash] opts the optional parameters
624
624
  # @option opts [String] :idempotency_key Optional client-generated unique key (e.g. a UUID) that makes retries safe. Same key + same body replays the original response; same key + different body → 422; key still processing → 409.
@@ -100,7 +100,7 @@ module Zernio
100
100
  end
101
101
 
102
102
  # Create conversation
103
- # Start a direct message conversation with a user. If a conversation with that recipient already exists, the message is added to the existing thread. Supported platforms: X, 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 template whose approved header format is LOCATION has no header asset to reconstruct at all: Meta only accepts the location at send time, so pass headerLocation (latitude and longitude required) whenever such a template is sent; headerMedia and headerLocation cannot both be supplied. - 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. - Template fields are accepted on the JSON body only, not on multipart requests. For a number you already have a thread with, this 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). 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).** 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 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.
103
+ # Start a direct message conversation with a user. If a conversation with that recipient already exists, the message is added to the existing thread. Supported platforms: X, 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 template whose approved header format is LOCATION has no header asset to reconstruct at all: Meta only accepts the location at send time, so pass headerLocation (latitude and longitude required) whenever such a template is sent; headerMedia and headerLocation cannot both be supplied. - 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. - CAROUSEL templates take per-card overrides via templateCards, each addressed by the card's card_index, because card body variables restart at {{1}} per card and cannot be expressed in the flat templateParams order. - Template fields are accepted on the JSON body only, not on multipart requests. For a number you already have a thread with, this 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). 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).** 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 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.
104
104
  # @param create_inbox_conversation_request [CreateInboxConversationRequest]
105
105
  # @param [Hash] opts the optional parameters
106
106
  # @return [CreateInboxConversation201Response]
@@ -110,7 +110,7 @@ module Zernio
110
110
  end
111
111
 
112
112
  # Create conversation
113
- # Start a direct message conversation with a user. If a conversation with that recipient already exists, the message is added to the existing thread. Supported platforms: X, 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 template whose approved header format is LOCATION has no header asset to reconstruct at all: Meta only accepts the location at send time, so pass headerLocation (latitude and longitude required) whenever such a template is sent; headerMedia and headerLocation cannot both be supplied. - 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. - Template fields are accepted on the JSON body only, not on multipart requests. For a number you already have a thread with, this 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). 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).** 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 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.
113
+ # Start a direct message conversation with a user. If a conversation with that recipient already exists, the message is added to the existing thread. Supported platforms: X, 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 template whose approved header format is LOCATION has no header asset to reconstruct at all: Meta only accepts the location at send time, so pass headerLocation (latitude and longitude required) whenever such a template is sent; headerMedia and headerLocation cannot both be supplied. - 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. - CAROUSEL templates take per-card overrides via templateCards, each addressed by the card's card_index, because card body variables restart at {{1}} per card and cannot be expressed in the flat templateParams order. - Template fields are accepted on the JSON body only, not on multipart requests. For a number you already have a thread with, this 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). 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).** 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 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.
114
114
  # @param create_inbox_conversation_request [CreateInboxConversationRequest]
115
115
  # @param [Hash] opts the optional parameters
116
116
  # @return [Array<(CreateInboxConversation201Response, Integer, Hash)>] CreateInboxConversation201Response data, response status code and response headers
@@ -110,7 +110,7 @@ module Zernio
110
110
  # @return true if the model is valid
111
111
  def valid?
112
112
  warn '[DEPRECATED] the `valid?` method is obsolete'
113
- code_validator = EnumAttributeValidator.new('String', ["PLATFORM_NOT_SUPPORTED", "PLATFORM_LIMITATION", "TEMPLATE_REQUIRED", "INVALID_TEMPLATE_PARAMS", "INVALID_TEMPLATE_BUTTON_PARAM", "DIRECT_SEND_NOT_ELIGIBLE", "DIRECT_SEND_LIMITED", "DIRECT_SEND_BLOCKED"])
113
+ code_validator = EnumAttributeValidator.new('String', ["PLATFORM_NOT_SUPPORTED", "PLATFORM_LIMITATION", "TEMPLATE_REQUIRED", "INVALID_TEMPLATE_PARAMS", "INVALID_TEMPLATE_BUTTON_PARAM", "INVALID_TEMPLATE_CARD_PARAM", "DIRECT_SEND_NOT_ELIGIBLE", "DIRECT_SEND_LIMITED", "DIRECT_SEND_BLOCKED"])
114
114
  return false unless code_validator.valid?(@code)
115
115
  true
116
116
  end
@@ -118,7 +118,7 @@ module Zernio
118
118
  # Custom attribute writer method checking allowed values (enum).
119
119
  # @param [Object] code Object to be assigned
120
120
  def code=(code)
121
- validator = EnumAttributeValidator.new('String', ["PLATFORM_NOT_SUPPORTED", "PLATFORM_LIMITATION", "TEMPLATE_REQUIRED", "INVALID_TEMPLATE_PARAMS", "INVALID_TEMPLATE_BUTTON_PARAM", "DIRECT_SEND_NOT_ELIGIBLE", "DIRECT_SEND_LIMITED", "DIRECT_SEND_BLOCKED"])
121
+ validator = EnumAttributeValidator.new('String', ["PLATFORM_NOT_SUPPORTED", "PLATFORM_LIMITATION", "TEMPLATE_REQUIRED", "INVALID_TEMPLATE_PARAMS", "INVALID_TEMPLATE_BUTTON_PARAM", "INVALID_TEMPLATE_CARD_PARAM", "DIRECT_SEND_NOT_ELIGIBLE", "DIRECT_SEND_LIMITED", "DIRECT_SEND_BLOCKED"])
122
122
  unless validator.valid?(code)
123
123
  fail ArgumentError, "invalid value for \"code\", must be one of #{validator.allowable_values}."
124
124
  end
@@ -48,6 +48,9 @@ module Zernio
48
48
  # WhatsApp only. Values for template buttons that carry one at send time, each addressed by the button's position in the approved template. This is the only way to send a copy-code button's payload (a Pix payment code, a coupon) or a flow token, because templateParams is a flat array of text variables and covers dynamic URL buttons only. Supplying a button here overrides whatever templateParams would have derived for that same index, so the send never carries one button twice; repeating an index within this array is rejected with 400. Each index must name a button of the matching kind on the approved template, which is also checked before the send and returns 400 (INVALID_TEMPLATE_BUTTON_PARAM) rather than a Meta rejection.
49
49
  attr_accessor :template_button_params
50
50
 
51
+ # WhatsApp only. Per-card overrides for a CAROUSEL template, each addressed by the card's card_index. Carousel card body variables restart at {{1}} per card, so they cannot be expressed in the flat templateParams slot order; use this instead. A cardIndex naming a card the approved template does not have, a duplicate cardIndex, or a params count that does not match the card body's token count is rejected with 400 (INVALID_TEMPLATE_CARD_PARAM).
52
+ attr_accessor :template_cards
53
+
51
54
  attr_accessor :header_media
52
55
 
53
56
  attr_accessor :header_location
@@ -88,6 +91,7 @@ module Zernio
88
91
  :'template_language' => :'templateLanguage',
89
92
  :'template_params' => :'templateParams',
90
93
  :'template_button_params' => :'templateButtonParams',
94
+ :'template_cards' => :'templateCards',
91
95
  :'header_media' => :'headerMedia',
92
96
  :'header_location' => :'headerLocation'
93
97
  }
@@ -117,6 +121,7 @@ module Zernio
117
121
  :'template_language' => :'String',
118
122
  :'template_params' => :'Array<String>',
119
123
  :'template_button_params' => :'Array<CreateInboxConversationRequestTemplateButtonParamsInner>',
124
+ :'template_cards' => :'Array<CreateInboxConversationRequestTemplateCardsInner>',
120
125
  :'header_media' => :'CreateInboxConversationRequestHeaderMedia',
121
126
  :'header_location' => :'CreateInboxConversationRequestHeaderLocation'
122
127
  }
@@ -198,6 +203,12 @@ module Zernio
198
203
  end
199
204
  end
200
205
 
206
+ if attributes.key?(:'template_cards')
207
+ if (value = attributes[:'template_cards']).is_a?(Array)
208
+ self.template_cards = value
209
+ end
210
+ end
211
+
201
212
  if attributes.key?(:'header_media')
202
213
  self.header_media = attributes[:'header_media']
203
214
  end
@@ -220,6 +231,10 @@ module Zernio
220
231
  invalid_properties.push('invalid value for "template_button_params", number of items must be less than or equal to 10.')
221
232
  end
222
233
 
234
+ if !@template_cards.nil? && @template_cards.length > 10
235
+ invalid_properties.push('invalid value for "template_cards", number of items must be less than or equal to 10.')
236
+ end
237
+
223
238
  invalid_properties
224
239
  end
225
240
 
@@ -231,6 +246,7 @@ module Zernio
231
246
  category_validator = EnumAttributeValidator.new('String', ["utility"])
232
247
  return false unless category_validator.valid?(@category)
233
248
  return false if !@template_button_params.nil? && @template_button_params.length > 10
249
+ return false if !@template_cards.nil? && @template_cards.length > 10
234
250
  true
235
251
  end
236
252
 
@@ -268,6 +284,20 @@ module Zernio
268
284
  @template_button_params = template_button_params
269
285
  end
270
286
 
287
+ # Custom attribute writer method with validation
288
+ # @param [Object] template_cards Value to be assigned
289
+ def template_cards=(template_cards)
290
+ if template_cards.nil?
291
+ fail ArgumentError, 'template_cards cannot be nil'
292
+ end
293
+
294
+ if template_cards.length > 10
295
+ fail ArgumentError, 'invalid value for "template_cards", number of items must be less than or equal to 10.'
296
+ end
297
+
298
+ @template_cards = template_cards
299
+ end
300
+
271
301
  # Checks equality by comparing each attribute.
272
302
  # @param [Object] Object to be compared
273
303
  def ==(o)
@@ -284,6 +314,7 @@ module Zernio
284
314
  template_language == o.template_language &&
285
315
  template_params == o.template_params &&
286
316
  template_button_params == o.template_button_params &&
317
+ template_cards == o.template_cards &&
287
318
  header_media == o.header_media &&
288
319
  header_location == o.header_location
289
320
  end
@@ -297,7 +328,7 @@ module Zernio
297
328
  # Calculates hash code according to all attributes.
298
329
  # @return [Integer] Hash code
299
330
  def hash
300
- [account_id, participant_id, participant_username, message, skip_dm_check, template_name, category, link_preview, template_language, template_params, template_button_params, header_media, header_location].hash
331
+ [account_id, participant_id, participant_username, message, skip_dm_check, template_name, category, link_preview, template_language, template_params, template_button_params, template_cards, header_media, header_location].hash
301
332
  end
302
333
 
303
334
  # Builds the object from hash
@@ -0,0 +1,235 @@
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 'date'
14
+ require 'time'
15
+
16
+ module Zernio
17
+ class CreateInboxConversationRequestTemplateCardsInner < ApiModelBase
18
+ # The card's card_index in the approved template.
19
+ attr_accessor :card_index
20
+
21
+ # Values for this card's own body variables, in the card's own {{1}}, {{2}}, ... order (or named-slot order of appearance).
22
+ attr_accessor :params
23
+
24
+ attr_accessor :header_media
25
+
26
+ # Values for this card's own buttons, each addressed by the button's index within the card.
27
+ attr_accessor :buttons
28
+
29
+ # Attribute mapping from ruby-style variable name to JSON key.
30
+ def self.attribute_map
31
+ {
32
+ :'card_index' => :'cardIndex',
33
+ :'params' => :'params',
34
+ :'header_media' => :'headerMedia',
35
+ :'buttons' => :'buttons'
36
+ }
37
+ end
38
+
39
+ # Returns attribute mapping this model knows about
40
+ def self.acceptable_attribute_map
41
+ attribute_map
42
+ end
43
+
44
+ # Returns all the JSON keys this model knows about
45
+ def self.acceptable_attributes
46
+ acceptable_attribute_map.values
47
+ end
48
+
49
+ # Attribute type mapping.
50
+ def self.openapi_types
51
+ {
52
+ :'card_index' => :'Integer',
53
+ :'params' => :'Array<String>',
54
+ :'header_media' => :'CreateInboxConversationRequestTemplateCardsInnerHeaderMedia',
55
+ :'buttons' => :'Array<CreateInboxConversationRequestTemplateCardsInnerButtonsInner>'
56
+ }
57
+ end
58
+
59
+ # List of attributes with nullable: true
60
+ def self.openapi_nullable
61
+ Set.new([
62
+ ])
63
+ end
64
+
65
+ # Initializes the object
66
+ # @param [Hash] attributes Model attributes in the form of hash
67
+ def initialize(attributes = {})
68
+ if (!attributes.is_a?(Hash))
69
+ fail ArgumentError, "The input argument (attributes) must be a hash in `Zernio::CreateInboxConversationRequestTemplateCardsInner` initialize method"
70
+ end
71
+
72
+ # check to see if the attribute exists and convert string to symbol for hash key
73
+ acceptable_attribute_map = self.class.acceptable_attribute_map
74
+ attributes = attributes.each_with_object({}) { |(k, v), h|
75
+ if (!acceptable_attribute_map.key?(k.to_sym))
76
+ fail ArgumentError, "`#{k}` is not a valid attribute in `Zernio::CreateInboxConversationRequestTemplateCardsInner`. Please check the name to make sure it's valid. List of attributes: " + acceptable_attribute_map.keys.inspect
77
+ end
78
+ h[k.to_sym] = v
79
+ }
80
+
81
+ if attributes.key?(:'card_index')
82
+ self.card_index = attributes[:'card_index']
83
+ else
84
+ self.card_index = nil
85
+ end
86
+
87
+ if attributes.key?(:'params')
88
+ if (value = attributes[:'params']).is_a?(Array)
89
+ self.params = value
90
+ end
91
+ end
92
+
93
+ if attributes.key?(:'header_media')
94
+ self.header_media = attributes[:'header_media']
95
+ end
96
+
97
+ if attributes.key?(:'buttons')
98
+ if (value = attributes[:'buttons']).is_a?(Array)
99
+ self.buttons = value
100
+ end
101
+ end
102
+ end
103
+
104
+ # Show invalid properties with the reasons. Usually used together with valid?
105
+ # @return Array for valid properties with the reasons
106
+ def list_invalid_properties
107
+ warn '[DEPRECATED] the `list_invalid_properties` method is obsolete'
108
+ invalid_properties = Array.new
109
+ if @card_index.nil?
110
+ invalid_properties.push('invalid value for "card_index", card_index cannot be nil.')
111
+ end
112
+
113
+ if @card_index > 9
114
+ invalid_properties.push('invalid value for "card_index", must be smaller than or equal to 9.')
115
+ end
116
+
117
+ if @card_index < 0
118
+ invalid_properties.push('invalid value for "card_index", must be greater than or equal to 0.')
119
+ end
120
+
121
+ if !@buttons.nil? && @buttons.length > 2
122
+ invalid_properties.push('invalid value for "buttons", number of items must be less than or equal to 2.')
123
+ end
124
+
125
+ invalid_properties
126
+ end
127
+
128
+ # Check to see if the all the properties in the model are valid
129
+ # @return true if the model is valid
130
+ def valid?
131
+ warn '[DEPRECATED] the `valid?` method is obsolete'
132
+ return false if @card_index.nil?
133
+ return false if @card_index > 9
134
+ return false if @card_index < 0
135
+ return false if !@buttons.nil? && @buttons.length > 2
136
+ true
137
+ end
138
+
139
+ # Custom attribute writer method with validation
140
+ # @param [Object] card_index Value to be assigned
141
+ def card_index=(card_index)
142
+ if card_index.nil?
143
+ fail ArgumentError, 'card_index cannot be nil'
144
+ end
145
+
146
+ if card_index > 9
147
+ fail ArgumentError, 'invalid value for "card_index", must be smaller than or equal to 9.'
148
+ end
149
+
150
+ if card_index < 0
151
+ fail ArgumentError, 'invalid value for "card_index", must be greater than or equal to 0.'
152
+ end
153
+
154
+ @card_index = card_index
155
+ end
156
+
157
+ # Custom attribute writer method with validation
158
+ # @param [Object] buttons Value to be assigned
159
+ def buttons=(buttons)
160
+ if buttons.nil?
161
+ fail ArgumentError, 'buttons cannot be nil'
162
+ end
163
+
164
+ if buttons.length > 2
165
+ fail ArgumentError, 'invalid value for "buttons", number of items must be less than or equal to 2.'
166
+ end
167
+
168
+ @buttons = buttons
169
+ end
170
+
171
+ # Checks equality by comparing each attribute.
172
+ # @param [Object] Object to be compared
173
+ def ==(o)
174
+ return true if self.equal?(o)
175
+ self.class == o.class &&
176
+ card_index == o.card_index &&
177
+ params == o.params &&
178
+ header_media == o.header_media &&
179
+ buttons == o.buttons
180
+ end
181
+
182
+ # @see the `==` method
183
+ # @param [Object] Object to be compared
184
+ def eql?(o)
185
+ self == o
186
+ end
187
+
188
+ # Calculates hash code according to all attributes.
189
+ # @return [Integer] Hash code
190
+ def hash
191
+ [card_index, params, header_media, buttons].hash
192
+ end
193
+
194
+ # Builds the object from hash
195
+ # @param [Hash] attributes Model attributes in the form of hash
196
+ # @return [Object] Returns the model itself
197
+ def self.build_from_hash(attributes)
198
+ return nil unless attributes.is_a?(Hash)
199
+ attributes = attributes.transform_keys(&:to_sym)
200
+ transformed_hash = {}
201
+ openapi_types.each_pair do |key, type|
202
+ if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
203
+ transformed_hash["#{key}"] = nil
204
+ elsif type =~ /\AArray<(.*)>/i
205
+ # check to ensure the input is an array given that the attribute
206
+ # is documented as an array but the input is not
207
+ if attributes[attribute_map[key]].is_a?(Array)
208
+ transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
209
+ end
210
+ elsif !attributes[attribute_map[key]].nil?
211
+ transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
212
+ end
213
+ end
214
+ new(transformed_hash)
215
+ end
216
+
217
+ # Returns the object in the form of hash
218
+ # @return [Hash] Returns the object in the form of hash
219
+ def to_hash
220
+ hash = {}
221
+ self.class.attribute_map.each_pair do |attr, param|
222
+ value = self.send(attr)
223
+ if value.nil?
224
+ is_nullable = self.class.openapi_nullable.include?(attr)
225
+ next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
226
+ end
227
+
228
+ hash[param] = _to_hash(value)
229
+ end
230
+ hash
231
+ end
232
+
233
+ end
234
+
235
+ end