late-sdk 0.0.885 → 0.0.887

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -0
  3. data/docs/AdCampaignsApi.md +1 -1
  4. data/docs/CreateCommentAutomationRequest.md +1 -1
  5. data/docs/RegisterWhatsAppNumberRequest.md +1 -1
  6. data/docs/RequestWhatsAppVerificationCode200Response.md +26 -0
  7. data/docs/RequestWhatsAppVerificationCodeRequest.md +20 -0
  8. data/docs/SendInboxMessage400Response.md +5 -1
  9. data/docs/VerifyWhatsAppNumber200Response.md +22 -0
  10. data/docs/VerifyWhatsAppNumberRequest.md +18 -0
  11. data/docs/WhatsAppApi.md +146 -0
  12. data/lib/zernio-sdk/api/ad_campaigns_api.rb +2 -2
  13. data/lib/zernio-sdk/api/whats_app_api.rb +144 -0
  14. data/lib/zernio-sdk/models/create_comment_automation_request.rb +1 -1
  15. data/lib/zernio-sdk/models/register_whats_app_number_request.rb +1 -1
  16. data/lib/zernio-sdk/models/request_whats_app_verification_code200_response.rb +183 -0
  17. data/lib/zernio-sdk/models/request_whats_app_verification_code_request.rb +195 -0
  18. data/lib/zernio-sdk/models/send_inbox_message400_response.rb +36 -4
  19. data/lib/zernio-sdk/models/update_ad_request_targeting.rb +1 -1
  20. data/lib/zernio-sdk/models/verify_whats_app_number200_response.rb +165 -0
  21. data/lib/zernio-sdk/models/verify_whats_app_number_request.rb +165 -0
  22. data/lib/zernio-sdk/version.rb +1 -1
  23. data/lib/zernio-sdk.rb +4 -0
  24. data/openapi.yaml +144 -12
  25. data/spec/api/ad_campaigns_api_spec.rb +1 -1
  26. data/spec/api/whats_app_api_spec.rb +26 -0
  27. data/spec/models/request_whats_app_verification_code200_response_spec.rb +60 -0
  28. data/spec/models/request_whats_app_verification_code_request_spec.rb +46 -0
  29. data/spec/models/send_inbox_message400_response_spec.rb +17 -1
  30. data/spec/models/verify_whats_app_number200_response_spec.rb +48 -0
  31. data/spec/models/verify_whats_app_number_request_spec.rb +36 -0
  32. data/zernio-sdk-0.0.887.gem +0 -0
  33. metadata +18 -2
  34. data/zernio-sdk-0.0.885.gem +0 -0
@@ -0,0 +1,165 @@
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 VerifyWhatsAppNumberRequest < ApiModelBase
18
+ # The 6-digit code Meta sent to the phone. Non-digit separators (e.g. \"749-456\") are stripped automatically.
19
+ attr_accessor :code
20
+
21
+ # Attribute mapping from ruby-style variable name to JSON key.
22
+ def self.attribute_map
23
+ {
24
+ :'code' => :'code'
25
+ }
26
+ end
27
+
28
+ # Returns attribute mapping this model knows about
29
+ def self.acceptable_attribute_map
30
+ attribute_map
31
+ end
32
+
33
+ # Returns all the JSON keys this model knows about
34
+ def self.acceptable_attributes
35
+ acceptable_attribute_map.values
36
+ end
37
+
38
+ # Attribute type mapping.
39
+ def self.openapi_types
40
+ {
41
+ :'code' => :'String'
42
+ }
43
+ end
44
+
45
+ # List of attributes with nullable: true
46
+ def self.openapi_nullable
47
+ Set.new([
48
+ ])
49
+ end
50
+
51
+ # Initializes the object
52
+ # @param [Hash] attributes Model attributes in the form of hash
53
+ def initialize(attributes = {})
54
+ if (!attributes.is_a?(Hash))
55
+ fail ArgumentError, "The input argument (attributes) must be a hash in `Zernio::VerifyWhatsAppNumberRequest` initialize method"
56
+ end
57
+
58
+ # check to see if the attribute exists and convert string to symbol for hash key
59
+ acceptable_attribute_map = self.class.acceptable_attribute_map
60
+ attributes = attributes.each_with_object({}) { |(k, v), h|
61
+ if (!acceptable_attribute_map.key?(k.to_sym))
62
+ fail ArgumentError, "`#{k}` is not a valid attribute in `Zernio::VerifyWhatsAppNumberRequest`. Please check the name to make sure it's valid. List of attributes: " + acceptable_attribute_map.keys.inspect
63
+ end
64
+ h[k.to_sym] = v
65
+ }
66
+
67
+ if attributes.key?(:'code')
68
+ self.code = attributes[:'code']
69
+ else
70
+ self.code = nil
71
+ end
72
+ end
73
+
74
+ # Show invalid properties with the reasons. Usually used together with valid?
75
+ # @return Array for valid properties with the reasons
76
+ def list_invalid_properties
77
+ warn '[DEPRECATED] the `list_invalid_properties` method is obsolete'
78
+ invalid_properties = Array.new
79
+ if @code.nil?
80
+ invalid_properties.push('invalid value for "code", code cannot be nil.')
81
+ end
82
+
83
+ invalid_properties
84
+ end
85
+
86
+ # Check to see if the all the properties in the model are valid
87
+ # @return true if the model is valid
88
+ def valid?
89
+ warn '[DEPRECATED] the `valid?` method is obsolete'
90
+ return false if @code.nil?
91
+ true
92
+ end
93
+
94
+ # Custom attribute writer method with validation
95
+ # @param [Object] code Value to be assigned
96
+ def code=(code)
97
+ if code.nil?
98
+ fail ArgumentError, 'code cannot be nil'
99
+ end
100
+
101
+ @code = code
102
+ end
103
+
104
+ # Checks equality by comparing each attribute.
105
+ # @param [Object] Object to be compared
106
+ def ==(o)
107
+ return true if self.equal?(o)
108
+ self.class == o.class &&
109
+ code == o.code
110
+ end
111
+
112
+ # @see the `==` method
113
+ # @param [Object] Object to be compared
114
+ def eql?(o)
115
+ self == o
116
+ end
117
+
118
+ # Calculates hash code according to all attributes.
119
+ # @return [Integer] Hash code
120
+ def hash
121
+ [code].hash
122
+ end
123
+
124
+ # Builds the object from hash
125
+ # @param [Hash] attributes Model attributes in the form of hash
126
+ # @return [Object] Returns the model itself
127
+ def self.build_from_hash(attributes)
128
+ return nil unless attributes.is_a?(Hash)
129
+ attributes = attributes.transform_keys(&:to_sym)
130
+ transformed_hash = {}
131
+ openapi_types.each_pair do |key, type|
132
+ if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
133
+ transformed_hash["#{key}"] = nil
134
+ elsif type =~ /\AArray<(.*)>/i
135
+ # check to ensure the input is an array given that the attribute
136
+ # is documented as an array but the input is not
137
+ if attributes[attribute_map[key]].is_a?(Array)
138
+ transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
139
+ end
140
+ elsif !attributes[attribute_map[key]].nil?
141
+ transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
142
+ end
143
+ end
144
+ new(transformed_hash)
145
+ end
146
+
147
+ # Returns the object in the form of hash
148
+ # @return [Hash] Returns the object in the form of hash
149
+ def to_hash
150
+ hash = {}
151
+ self.class.attribute_map.each_pair do |attr, param|
152
+ value = self.send(attr)
153
+ if value.nil?
154
+ is_nullable = self.class.openapi_nullable.include?(attr)
155
+ next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
156
+ end
157
+
158
+ hash[param] = _to_hash(value)
159
+ end
160
+ hash
161
+ end
162
+
163
+ end
164
+
165
+ end
@@ -11,5 +11,5 @@ Generator version: 7.19.0
11
11
  =end
12
12
 
13
13
  module Zernio
14
- VERSION = '0.0.885'
14
+ VERSION = '0.0.887'
15
15
  end
data/lib/zernio-sdk.rb CHANGED
@@ -1308,6 +1308,8 @@ require 'zernio-sdk/models/reply_to_phone_number_reviewer_request'
1308
1308
  require 'zernio-sdk/models/reply_to_phone_number_reviewer_request_attachments_inner'
1309
1309
  require 'zernio-sdk/models/request_sms_sender_id_limit_increase200_response'
1310
1310
  require 'zernio-sdk/models/request_sms_sender_id_limit_increase_request'
1311
+ require 'zernio-sdk/models/request_whats_app_verification_code200_response'
1312
+ require 'zernio-sdk/models/request_whats_app_verification_code_request'
1311
1313
  require 'zernio-sdk/models/resend_sms_registration_otp200_response'
1312
1314
  require 'zernio-sdk/models/reserve_rf_prediction201_response'
1313
1315
  require 'zernio-sdk/models/reserve_rf_prediction_request'
@@ -1786,6 +1788,8 @@ require 'zernio-sdk/models/verify_credential200_response'
1786
1788
  require 'zernio-sdk/models/verify_sms_registration_otp200_response'
1787
1789
  require 'zernio-sdk/models/verify_sms_registration_otp_request'
1788
1790
  require 'zernio-sdk/models/verify_whats_app_caller_id_request'
1791
+ require 'zernio-sdk/models/verify_whats_app_number200_response'
1792
+ require 'zernio-sdk/models/verify_whats_app_number_request'
1789
1793
  require 'zernio-sdk/models/vote_reddit_thing_request'
1790
1794
  require 'zernio-sdk/models/webhook'
1791
1795
  require 'zernio-sdk/models/webhook_log'
data/openapi.yaml CHANGED
@@ -17802,7 +17802,7 @@ paths:
17802
17802
  pin:
17803
17803
  type: string
17804
17804
  pattern: '^\d{6}$'
17805
- description: 'The 6-digit two-step verification PIN set on the number. Omit it only if the number has no PIN of its own.'
17805
+ description: 'The 6-digit two-step verification PIN set on the number. Omitting it applies Zernio''s managed default registration PIN, the same one every Embedded Signup connect sets automatically.'
17806
17806
  example:
17807
17807
  pin: "481902"
17808
17808
  responses:
@@ -17824,6 +17824,124 @@ paths:
17824
17824
  description: WhatsApp account not found
17825
17825
  '422':
17826
17826
  description: 'Meta rejected the registration (e.g. PIN mismatch), or the number cannot be registered through the API.'
17827
+ /v1/accounts/{accountId}/whatsapp/request-code:
17828
+ post:
17829
+ x-resource-group: "accounts"
17830
+ operationId: requestWhatsAppVerificationCode
17831
+ tags: [WhatsApp]
17832
+ summary: Request a Meta re-verification code for a BYO WhatsApp number
17833
+ description: |
17834
+ For a bring-your-own WhatsApp number (its own WABA, migrated off another BSP) that
17835
+ Meta demoted to re-verification, this requests a new OTP from Meta. The code lands
17836
+ on the customer's own handset, so verifying it is necessarily self-service; call
17837
+ POST /v1/accounts/{accountId}/whatsapp/verify-code with the code once it arrives.
17838
+ Rate-limited to one request per 10 minutes per account, and Meta enforces its own
17839
+ cooldown on top of that.
17840
+ parameters:
17841
+ - name: accountId
17842
+ in: path
17843
+ required: true
17844
+ schema: { type: string }
17845
+ description: The WhatsApp account ID
17846
+ requestBody:
17847
+ required: false
17848
+ content:
17849
+ application/json:
17850
+ schema:
17851
+ type: object
17852
+ properties:
17853
+ method:
17854
+ type: string
17855
+ enum: [SMS, VOICE]
17856
+ default: SMS
17857
+ language:
17858
+ type: string
17859
+ default: en_US
17860
+ description: 'Meta locale code for the verification message, e.g. en_US.'
17861
+ responses:
17862
+ '200':
17863
+ description: 'Code requested, or the number was already CONNECTED and no code was needed.'
17864
+ content:
17865
+ application/json:
17866
+ schema:
17867
+ type: object
17868
+ properties:
17869
+ requested: { type: boolean }
17870
+ alreadyActive: { type: boolean }
17871
+ method: { type: string }
17872
+ accountId: { type: string }
17873
+ phoneNumberId: { type: string }
17874
+ '400': { $ref: '#/components/responses/BadRequest' }
17875
+ '401': { $ref: '#/components/responses/Unauthorized' }
17876
+ '404': { $ref: '#/components/responses/NotFound' }
17877
+ '409':
17878
+ description: 'Meta already reports this number as VERIFIED. Call POST /v1/accounts/{accountId}/whatsapp/register instead.'
17879
+ '422':
17880
+ description: 'The account has no phone number bound yet, it runs in coexistence with the WhatsApp Business app, or Meta rejected the code request.'
17881
+ '429':
17882
+ description: 'Our own 10-minute-per-account cooldown is active, or Meta has escalated to a multi-hour lockout after repeated attempts.'
17883
+ headers:
17884
+ Retry-After:
17885
+ description: 'Seconds remaining until the cooldown or lockout clears.'
17886
+ schema: { type: integer }
17887
+ content:
17888
+ application/json:
17889
+ schema: { $ref: '#/components/schemas/ErrorResponse' }
17890
+ '503':
17891
+ description: "Meta could not dispatch a code for this number yet. Retry shortly."
17892
+ headers:
17893
+ Retry-After:
17894
+ description: 'Seconds to wait before retrying.'
17895
+ schema: { type: integer }
17896
+ content:
17897
+ application/json:
17898
+ schema: { $ref: '#/components/schemas/ErrorResponse' }
17899
+ /v1/accounts/{accountId}/whatsapp/verify-code:
17900
+ post:
17901
+ x-resource-group: "accounts"
17902
+ operationId: verifyWhatsAppNumber
17903
+ tags: [WhatsApp]
17904
+ summary: Verify the Meta re-verification code for a BYO WhatsApp number
17905
+ description: |
17906
+ Submits the OTP Meta sent in response to POST /v1/accounts/{accountId}/whatsapp/request-code.
17907
+ This only verifies the number with Meta; it does not register it on the Cloud API.
17908
+ Call POST /v1/accounts/{accountId}/whatsapp/register afterward to complete activation.
17909
+ parameters:
17910
+ - name: accountId
17911
+ in: path
17912
+ required: true
17913
+ schema: { type: string }
17914
+ description: The WhatsApp account ID
17915
+ requestBody:
17916
+ required: true
17917
+ content:
17918
+ application/json:
17919
+ schema:
17920
+ type: object
17921
+ required: [code]
17922
+ properties:
17923
+ code:
17924
+ type: string
17925
+ description: 'The 6-digit code Meta sent to the phone. Non-digit separators (e.g. "749-456") are stripped automatically.'
17926
+ example:
17927
+ code: "749456"
17928
+ responses:
17929
+ '200':
17930
+ description: Number verified with Meta
17931
+ content:
17932
+ application/json:
17933
+ schema:
17934
+ type: object
17935
+ properties:
17936
+ verified: { type: boolean }
17937
+ accountId: { type: string }
17938
+ phoneNumberId: { type: string }
17939
+ '400':
17940
+ description: 'The code is malformed, or Meta rejected it as wrong or expired.'
17941
+ '401': { $ref: '#/components/responses/Unauthorized' }
17942
+ '404': { $ref: '#/components/responses/NotFound' }
17943
+ '422':
17944
+ description: 'The account has no phone number bound to it yet.'
17827
17945
  /v1/accounts/{accountId}/health:
17828
17946
  get:
17829
17947
  x-resource-group: "accounts"
@@ -29208,17 +29326,24 @@ paths:
29208
29326
  fbtraceId: { type: string, description: "Meta fbtrace_id, quote this in a Meta bug report" }
29209
29327
  type: { type: string, description: "Meta error type (e.g. OAuthException)" }
29210
29328
  '400':
29211
- description: 'Bad request (e.g., attachment not supported for platform, validation error, category combined with a template or attachment, category used on a non-WhatsApp account, or the WhatsApp Business Account is not eligible for Direct Send)'
29329
+ description: 'Bad request (e.g., attachment not supported for platform, validation error, category combined with a template or attachment, category used on a non-WhatsApp account, or the WhatsApp Business Account is not eligible for Direct Send). Meta rejections (e.g. sending outside the messaging window) arrive with code platform_api_error, type platform_error, and platform + platformError set.'
29212
29330
  content:
29213
29331
  application/json:
29214
29332
  schema:
29215
29333
  type: object
29216
29334
  properties:
29217
29335
  error: { type: string }
29336
+ type:
29337
+ type: string
29338
+ description: "Present on Meta pass-through rejections: platform_error when Meta rejected the send (see platform/platformError below), invalid_request_error for validation failures."
29339
+ enum: [platform_error, invalid_request_error]
29218
29340
  code:
29219
29341
  type: string
29220
- description: "Stable machine-readable reason. PLATFORM_LIMITATION covers a capability the platform does not offer (e.g. Bluesky and Reddit DMs reject media); MISSING_PARTICIPANT means the stored conversation has no recipient to send to; DIRECT_SEND_NOT_ELIGIBLE and DIRECT_SEND_BLOCKED mean the WhatsApp Business Account needs Meta to grant or restore Direct Send access; DIRECT_SEND_LIMITED is temporary, Meta lifts it on its own."
29221
- enum: [PLATFORM_LIMITATION, MISSING_PARTICIPANT, DIRECT_SEND_NOT_ELIGIBLE, DIRECT_SEND_LIMITED, DIRECT_SEND_BLOCKED]
29342
+ description: "Stable machine-readable reason. PLATFORM_LIMITATION covers a capability the platform does not offer (e.g. Bluesky and Reddit DMs reject media); MISSING_PARTICIPANT means the stored conversation has no recipient to send to; DIRECT_SEND_NOT_ELIGIBLE and DIRECT_SEND_BLOCKED mean the WhatsApp Business Account needs Meta to grant or restore Direct Send access; DIRECT_SEND_LIMITED is temporary, Meta lifts it on its own; platform_api_error means Meta itself rejected the send (see platformError)."
29343
+ enum: [PLATFORM_LIMITATION, MISSING_PARTICIPANT, DIRECT_SEND_NOT_ELIGIBLE, DIRECT_SEND_LIMITED, DIRECT_SEND_BLOCKED, platform_api_error]
29344
+ platform:
29345
+ type: string
29346
+ description: "Present alongside code platform_api_error. The platform that rejected the send (e.g. instagram, facebook)."
29222
29347
  platformError:
29223
29348
  type: object
29224
29349
  description: "Instagram/Facebook only. Meta's own diagnostic fields for the rejected send, passed through verbatim so you can tell failure classes apart and quote them to Meta. Absent when the failure did not come from Meta."
@@ -29234,9 +29359,14 @@ paths:
29234
29359
  upstream failure (for example WhatsApp 131000) does not say whether
29235
29360
  the message was delivered. Retrying this request may deliver the
29236
29361
  message twice. Retry only if your use case tolerates a duplicate.
29362
+ Meta 5xx failures also arrive as a platform_error envelope (code
29363
+ platform_api_error, with platform and platformError set).
29237
29364
  '401': { $ref: '#/components/responses/Unauthorized' }
29238
29365
  '403':
29239
- description: Inbox addon required
29366
+ description: 'Inbox addon required, or Meta rejected the send outside the messaging window (type platform_error, code platform_api_error, platform, platformError with code/subcode/fbtraceId/type)'
29367
+ content:
29368
+ application/json:
29369
+ schema: { $ref: '#/components/schemas/ErrorResponse' }
29240
29370
  '409': { $ref: '#/components/responses/IdempotencyKeyInFlight' }
29241
29371
  '422': { $ref: '#/components/responses/IdempotencyKeyReused' }
29242
29372
 
@@ -41650,7 +41780,7 @@ paths:
41650
41780
  accountId: { type: string, description: Instagram or Facebook account ID }
41651
41781
  trigger: { type: string, enum: [comment, story_reply], default: comment, description: "What fires the automation. 'comment' (keyword comment on a post) or 'story_reply' (keyword reply to an Instagram story). For 'story_reply', platformPostId is the story media id (omit for any story)." }
41652
41782
  platformPostId: { type: string, description: "Platform media/post ID (or story media id when trigger=story_reply). Omit for an account-wide (any-post / any-story) automation." }
41653
- postId: { type: string, description: "Zernio post ID. Required only when also targeting a specific post via platformPostId." }
41783
+ postId: { type: string, description: "Zernio post ID. Optional and never required. Use it INSTEAD of platformPostId to bind a per-post automation to a not-yet-published Zernio post: the automation stays pending and arms itself when that post publishes. For a post already live on the platform, pass platformPostId alone and omit this." }
41654
41784
  postTitle: { type: string, description: Post content snippet for display }
41655
41785
  name: { type: string, description: Automation label }
41656
41786
  keywords:
@@ -44075,9 +44205,11 @@ paths:
44075
44205
  list are removed); a kind left out is untouched. Any other `targeting` field
44076
44206
  returns 400: Google cannot mutate broad targeting post-create without recreating
44077
44207
  the campaign. `creative` returns 501.
44078
- - **LinkedIn**: status, budget, targeting (geo countries only, applied to the
44079
- LinkedIn Campaign via PARTIAL_UPDATE), and creative (uploads new media, creates a
44080
- replacement inline creative on the same campaign, pauses the old one).
44208
+ - **LinkedIn**: status, budget, targeting (countries or regions, excludedLocations (countries),
44209
+ the B2B facets, and audience segments; applied to the LinkedIn Campaign via
44210
+ PARTIAL_UPDATE, and REPLACES the campaign's entire targetingCriteria, not a merge),
44211
+ and creative (uploads new media, creates a replacement inline creative on the same
44212
+ campaign, pauses the old one).
44081
44213
  - **Pinterest / X / OpenAI Ads**: status + budget only. Sending
44082
44214
  `targeting` or `creative` returns 501 with code `unsupported_platform_operation`.
44083
44215
  OpenAI Ads budget is lifetime-only (see `budget.type` below).
@@ -44128,8 +44260,8 @@ paths:
44128
44260
  type: object
44129
44261
  description: |
44130
44262
  Meta + TikTok (demographics/interests), Google (keyword and device
44131
- bid adjustment edits only), and LinkedIn (geo countries). Pinterest / X
44132
- return 501.
44263
+ bid adjustment edits only), and LinkedIn (countries or regions required).
44264
+ Pinterest / X return 501.
44133
44265
  properties:
44134
44266
  keywords:
44135
44267
  type: array
@@ -44230,7 +44362,7 @@ paths:
44230
44362
  ad: { $ref: '#/components/schemas/Ad' }
44231
44363
  message: { type: string }
44232
44364
  '400':
44233
- description: 'Invalid status transition, budget below minimum, or a LinkedIn creative update without imageUrl or videoUrl'
44365
+ description: 'Invalid status transition, budget below minimum, a LinkedIn creative update without imageUrl or videoUrl, or a LinkedIn targeting update without countries or regions'
44234
44366
  '401': { $ref: '#/components/responses/Unauthorized' }
44235
44367
  '403':
44236
44368
  description: 'Returned with code `ads_allowance_exceeded` when the team has no payment method on file and has reached the 500 free live ads: add a card to resume.'
@@ -453,7 +453,7 @@ describe 'AdCampaignsApi' do
453
453
 
454
454
  # unit tests for update_ad
455
455
  # Update ad
456
- # Patch one or more fields on an ad. Status, budget, targeting, and creative changes are propagated to the platform. Per-platform support: - **Meta** (Facebook + Instagram): all fields supported. - **TikTok**: status, budget, targeting (via &#x60;/v2/adgroup/update/&#x60;), and creative (via &#x60;/v2/ad/update/&#x60; patch-style: &#x60;headline&#x60; is ignored, &#x60;body&#x60; becomes &#x60;ad_text&#x60;). - **Google**: status, budget, KEYWORD edits via &#x60;targeting.keywords&#x60; / &#x60;targeting.negativeKeywords&#x60;, and DEVICE bid adjustments via &#x60;targeting.devices&#x60;. Each list you send becomes the FULL new set of its kind (criteria not in the list are removed); a kind left out is untouched. Any other &#x60;targeting&#x60; field returns 400: Google cannot mutate broad targeting post-create without recreating the campaign. &#x60;creative&#x60; returns 501. - **LinkedIn**: status, budget, targeting (geo countries only, applied to the LinkedIn Campaign via PARTIAL_UPDATE), and creative (uploads new media, creates a replacement inline creative on the same campaign, pauses the old one). - **Pinterest / X / OpenAI Ads**: status + budget only. Sending &#x60;targeting&#x60; or &#x60;creative&#x60; returns 501 with code &#x60;unsupported_platform_operation&#x60;. OpenAI Ads budget is lifetime-only (see &#x60;budget.type&#x60; below). **Google keyword replacement:** These edits affect the ad&#39;s entire ad group, including sibling ads. Positive (&#x60;targeting.keywords&#x60;) and negative (&#x60;targeting.negativeKeywords&#x60;) sets are independent: omit a field to leave that set unchanged, or send &#x60;[]&#x60; to remove every keyword of that kind. Zernio compares each supplied set with Google&#39;s live criteria by case-insensitive keyword text and match type. A matching criterion is left untouched, retaining its criterion ID, enabled/paused status, keyword-level bid overrides, labels, and criterion-associated history/statistics. Zernio does not reset its quality score; Google continues to calculate scores and statistics normally. Text comparison does not trim whitespace. A bare string or an object without &#x60;matchType&#x60; means &#x60;broad&#x60;, not the existing criterion&#39;s match type. For example, resending an existing &#x60;{ \&quot;text\&quot;: \&quot;plumber\&quot;, \&quot;matchType\&quot;: \&quot;exact\&quot; }&#x60; preserves it; sending &#x60;\&quot;plumber\&quot;&#x60; instead removes that EXACT criterion and requests a BROAD one. Changing text or match type removes criteria no longer requested and creates any missing criteria. New criteria get new IDs and do not inherit removed criteria&#39;s bid overrides, labels, or history. Historical reporting for a removed criterion is not transferred to its replacement. To add keywords without replacing a set, use [POST /v1/ads/keywords](https://docs.zernio.com/ad-campaigns/add-ad-keywords). Use &#x60;PATCH /v1/ads/keywords/{keywordId}&#x60; to pause/enable one keyword, or &#x60;DELETE /v1/ads/keywords/{keywordId}&#x60; to remove it.
456
+ # Patch one or more fields on an ad. Status, budget, targeting, and creative changes are propagated to the platform. Per-platform support: - **Meta** (Facebook + Instagram): all fields supported. - **TikTok**: status, budget, targeting (via &#x60;/v2/adgroup/update/&#x60;), and creative (via &#x60;/v2/ad/update/&#x60; patch-style: &#x60;headline&#x60; is ignored, &#x60;body&#x60; becomes &#x60;ad_text&#x60;). - **Google**: status, budget, KEYWORD edits via &#x60;targeting.keywords&#x60; / &#x60;targeting.negativeKeywords&#x60;, and DEVICE bid adjustments via &#x60;targeting.devices&#x60;. Each list you send becomes the FULL new set of its kind (criteria not in the list are removed); a kind left out is untouched. Any other &#x60;targeting&#x60; field returns 400: Google cannot mutate broad targeting post-create without recreating the campaign. &#x60;creative&#x60; returns 501. - **LinkedIn**: status, budget, targeting (countries or regions, excludedLocations (countries), the B2B facets, and audience segments; applied to the LinkedIn Campaign via PARTIAL_UPDATE, and REPLACES the campaign&#39;s entire targetingCriteria, not a merge), and creative (uploads new media, creates a replacement inline creative on the same campaign, pauses the old one). - **Pinterest / X / OpenAI Ads**: status + budget only. Sending &#x60;targeting&#x60; or &#x60;creative&#x60; returns 501 with code &#x60;unsupported_platform_operation&#x60;. OpenAI Ads budget is lifetime-only (see &#x60;budget.type&#x60; below). **Google keyword replacement:** These edits affect the ad&#39;s entire ad group, including sibling ads. Positive (&#x60;targeting.keywords&#x60;) and negative (&#x60;targeting.negativeKeywords&#x60;) sets are independent: omit a field to leave that set unchanged, or send &#x60;[]&#x60; to remove every keyword of that kind. Zernio compares each supplied set with Google&#39;s live criteria by case-insensitive keyword text and match type. A matching criterion is left untouched, retaining its criterion ID, enabled/paused status, keyword-level bid overrides, labels, and criterion-associated history/statistics. Zernio does not reset its quality score; Google continues to calculate scores and statistics normally. Text comparison does not trim whitespace. A bare string or an object without &#x60;matchType&#x60; means &#x60;broad&#x60;, not the existing criterion&#39;s match type. For example, resending an existing &#x60;{ \&quot;text\&quot;: \&quot;plumber\&quot;, \&quot;matchType\&quot;: \&quot;exact\&quot; }&#x60; preserves it; sending &#x60;\&quot;plumber\&quot;&#x60; instead removes that EXACT criterion and requests a BROAD one. Changing text or match type removes criteria no longer requested and creates any missing criteria. New criteria get new IDs and do not inherit removed criteria&#39;s bid overrides, labels, or history. Historical reporting for a removed criterion is not transferred to its replacement. To add keywords without replacing a set, use [POST /v1/ads/keywords](https://docs.zernio.com/ad-campaigns/add-ad-keywords). Use &#x60;PATCH /v1/ads/keywords/{keywordId}&#x60; to pause/enable one keyword, or &#x60;DELETE /v1/ads/keywords/{keywordId}&#x60; to remove it.
457
457
  # @param ad_id
458
458
  # @param update_ad_request
459
459
  # @param [Hash] opts the optional parameters
@@ -422,6 +422,19 @@ describe 'WhatsAppApi' do
422
422
  end
423
423
  end
424
424
 
425
+ # unit tests for request_whats_app_verification_code
426
+ # Request a Meta re-verification code for a BYO WhatsApp number
427
+ # For a bring-your-own WhatsApp number (its own WABA, migrated off another BSP) that Meta demoted to re-verification, this requests a new OTP from Meta. The code lands on the customer&#39;s own handset, so verifying it is necessarily self-service; call POST /v1/accounts/{accountId}/whatsapp/verify-code with the code once it arrives. Rate-limited to one request per 10 minutes per account, and Meta enforces its own cooldown on top of that.
428
+ # @param account_id The WhatsApp account ID
429
+ # @param [Hash] opts the optional parameters
430
+ # @option opts [RequestWhatsAppVerificationCodeRequest] :request_whats_app_verification_code_request
431
+ # @return [RequestWhatsAppVerificationCode200Response]
432
+ describe 'request_whats_app_verification_code test' do
433
+ it 'should work' do
434
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
435
+ end
436
+ end
437
+
425
438
  # unit tests for send_whats_app_conversion
426
439
  # Send WhatsApp conversion event
427
440
  # Forward a WhatsApp Business Messaging conversion event (&#x60;LeadSubmitted&#x60;, &#x60;Purchase&#x60;, &#x60;AddToCart&#x60;, &#x60;InitiateCheckout&#x60;, &#x60;ViewContent&#x60;) to Meta&#39;s Conversions API with &#x60;action_source &#x3D; business_messaging&#x60; and &#x60;messaging_channel &#x3D; whatsapp&#x60;. The endpoint looks up the originating CTWA click ID (&#x60;ctwa_clid&#x60;) captured on the first inbound message of the conversation and replays it on every event so Meta can attribute the conversion back to the Click-to-WhatsApp ad that drove the chat. Configuration prerequisite on the WhatsApp account metadata: - &#x60;metaCapiDatasetId&#x60;: the Meta dataset ID linked to the WABA. Provision one with &#x60;POST /v1/whatsapp/dataset&#x60;. The WABA ID (already set automatically at connect time) is forwarded as &#x60;user_data.whatsapp_business_account_id&#x60;, which is the per-channel attribution identifier Meta requires for WhatsApp events. No Facebook Page ID is needed (that field is the Messenger-branch identifier). Identify the conversation by either &#x60;conversationId&#x60; (preferred) or &#x60;phoneE164&#x60; (digits only, no &#x60;+&#x60;). At least one is required. If the conversation has no captured &#x60;ctwa_clid&#x60;, the request returns 422 because there is nothing to attribute. Token and dataset coupling: the WhatsApp account&#39;s accessToken must have access to the configured &#x60;metaCapiDatasetId&#x60;. By default a WABA&#39;s system-user token is scoped to the WABA&#39;s own Business Manager and cannot post to a pixel owned by a different Business; Meta returns code 100 in that case. Either share the dataset with the WhatsApp app&#39;s Business in BM, or use a dataset already in the same Business as the WABA.
@@ -535,4 +548,17 @@ describe 'WhatsAppApi' do
535
548
  end
536
549
  end
537
550
 
551
+ # unit tests for verify_whats_app_number
552
+ # Verify the Meta re-verification code for a BYO WhatsApp number
553
+ # Submits the OTP Meta sent in response to POST /v1/accounts/{accountId}/whatsapp/request-code. This only verifies the number with Meta; it does not register it on the Cloud API. Call POST /v1/accounts/{accountId}/whatsapp/register afterward to complete activation.
554
+ # @param account_id The WhatsApp account ID
555
+ # @param verify_whats_app_number_request
556
+ # @param [Hash] opts the optional parameters
557
+ # @return [VerifyWhatsAppNumber200Response]
558
+ describe 'verify_whats_app_number test' do
559
+ it 'should work' do
560
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
561
+ end
562
+ end
563
+
538
564
  end
@@ -0,0 +1,60 @@
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::RequestWhatsAppVerificationCode200Response
18
+ # Automatically generated by openapi-generator (https://openapi-generator.tech)
19
+ # Please update as you see appropriate
20
+ describe Zernio::RequestWhatsAppVerificationCode200Response do
21
+ #let(:instance) { Zernio::RequestWhatsAppVerificationCode200Response.new }
22
+
23
+ describe 'test an instance of RequestWhatsAppVerificationCode200Response' do
24
+ it 'should create an instance of RequestWhatsAppVerificationCode200Response' do
25
+ # uncomment below to test the instance creation
26
+ #expect(instance).to be_instance_of(Zernio::RequestWhatsAppVerificationCode200Response)
27
+ end
28
+ end
29
+
30
+ describe 'test attribute "requested"' 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 "already_active"' 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 "method"' 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 "account_id"' 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
+ describe 'test attribute "phone_number_id"' do
55
+ it 'should work' do
56
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
57
+ end
58
+ end
59
+
60
+ 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::RequestWhatsAppVerificationCodeRequest
18
+ # Automatically generated by openapi-generator (https://openapi-generator.tech)
19
+ # Please update as you see appropriate
20
+ describe Zernio::RequestWhatsAppVerificationCodeRequest do
21
+ #let(:instance) { Zernio::RequestWhatsAppVerificationCodeRequest.new }
22
+
23
+ describe 'test an instance of RequestWhatsAppVerificationCodeRequest' do
24
+ it 'should create an instance of RequestWhatsAppVerificationCodeRequest' do
25
+ # uncomment below to test the instance creation
26
+ #expect(instance).to be_instance_of(Zernio::RequestWhatsAppVerificationCodeRequest)
27
+ end
28
+ end
29
+
30
+ describe 'test attribute "method"' 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', ["SMS", "VOICE"])
34
+ # validator.allowable_values.each do |value|
35
+ # expect { instance.method = value }.not_to raise_error
36
+ # end
37
+ end
38
+ end
39
+
40
+ describe 'test attribute "language"' 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
@@ -33,16 +33,32 @@ describe Zernio::SendInboxMessage400Response do
33
33
  end
34
34
  end
35
35
 
36
+ describe 'test attribute "type"' do
37
+ it 'should work' do
38
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
39
+ # validator = Petstore::EnumTest::EnumAttributeValidator.new('String', ["platform_error", "invalid_request_error"])
40
+ # validator.allowable_values.each do |value|
41
+ # expect { instance.type = value }.not_to raise_error
42
+ # end
43
+ end
44
+ end
45
+
36
46
  describe 'test attribute "code"' do
37
47
  it 'should work' do
38
48
  # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
39
- # validator = Petstore::EnumTest::EnumAttributeValidator.new('String', ["PLATFORM_LIMITATION", "MISSING_PARTICIPANT", "DIRECT_SEND_NOT_ELIGIBLE", "DIRECT_SEND_LIMITED", "DIRECT_SEND_BLOCKED"])
49
+ # validator = Petstore::EnumTest::EnumAttributeValidator.new('String', ["PLATFORM_LIMITATION", "MISSING_PARTICIPANT", "DIRECT_SEND_NOT_ELIGIBLE", "DIRECT_SEND_LIMITED", "DIRECT_SEND_BLOCKED", "platform_api_error"])
40
50
  # validator.allowable_values.each do |value|
41
51
  # expect { instance.code = value }.not_to raise_error
42
52
  # end
43
53
  end
44
54
  end
45
55
 
56
+ describe 'test attribute "platform"' do
57
+ it 'should work' do
58
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
59
+ end
60
+ end
61
+
46
62
  describe 'test attribute "platform_error"' do
47
63
  it 'should work' do
48
64
  # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/