zernio-sdk 1.4.330__tar.gz → 1.4.332__tar.gz

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 (156) hide show
  1. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/PKG-INFO +2 -1
  2. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/README.md +1 -0
  3. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/openapi.yaml +120 -10
  4. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/pyproject.toml +1 -1
  5. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/__init__.py +1 -1
  6. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/mcp/generated_tools.py +77 -6
  7. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/models/_generated/models.py +1 -1
  8. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/ad_campaigns.py +62 -0
  9. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/phone_numbers.py +16 -2
  10. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/whatsapp_phone_numbers.py +12 -2
  11. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/uv.lock +1 -1
  12. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/.dockerignore +0 -0
  13. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/.env.example +0 -0
  14. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/.github/CODEOWNERS +0 -0
  15. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/.github/workflows/generate.yml +0 -0
  16. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/.github/workflows/release-preview.yml +0 -0
  17. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/.github/workflows/release.yml +0 -0
  18. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/.github/workflows/test.yml +0 -0
  19. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/.gitignore +0 -0
  20. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/CHANGELOG.md +0 -0
  21. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/Dockerfile +0 -0
  22. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/Dockerfile.docker +0 -0
  23. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/LICENSE +0 -0
  24. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/claude-desktop-config.json +0 -0
  25. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/docs/HTTP_DEPLOYMENT.md +0 -0
  26. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/docs/MCP.md +0 -0
  27. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/examples/01_basic_usage.py +0 -0
  28. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/examples/02_schedule_from_csv.py +0 -0
  29. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/examples/03_cross_posting.py +0 -0
  30. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/examples/04_ai_content_generation.py +0 -0
  31. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/examples/05_download_tools.py +0 -0
  32. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/examples/data/sample_posts.csv +0 -0
  33. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/examples/publish_post.py +0 -0
  34. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/railway.toml +0 -0
  35. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/scripts/generate_examples.py +0 -0
  36. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/scripts/generate_mcp_docs.py +0 -0
  37. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/scripts/generate_mcp_tools.py +0 -0
  38. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/scripts/generate_models.py +0 -0
  39. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/scripts/generate_readme_reference.py +0 -0
  40. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/scripts/generate_resources.py +0 -0
  41. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/scripts/smoketest_streamable_http.py +0 -0
  42. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/server.json +0 -0
  43. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/ai/__init__.py +0 -0
  44. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/ai/content_generator.py +0 -0
  45. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/ai/protocols.py +0 -0
  46. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/ai/providers/__init__.py +0 -0
  47. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/ai/providers/openai.py +0 -0
  48. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/client/__init__.py +0 -0
  49. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/client/base.py +0 -0
  50. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/client/exceptions.py +0 -0
  51. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/client/late_client.py +0 -0
  52. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/client/rate_limiter.py +0 -0
  53. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/enums.py +0 -0
  54. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/mcp/__init__.py +0 -0
  55. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/mcp/__main__.py +0 -0
  56. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/mcp/auth.py +0 -0
  57. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/mcp/config.py +0 -0
  58. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/mcp/constants.py +0 -0
  59. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/mcp/http_server.py +0 -0
  60. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/mcp/server.py +0 -0
  61. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/mcp/tool_definitions.py +0 -0
  62. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/models/__init__.py +0 -0
  63. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/models/_generated/__init__.py +0 -0
  64. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/models/responses.py +0 -0
  65. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/pipelines/__init__.py +0 -0
  66. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/pipelines/cross_poster.py +0 -0
  67. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/pipelines/csv_scheduler.py +0 -0
  68. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/__init__.py +0 -0
  69. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/__init__.py +0 -0
  70. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/account_groups.py +0 -0
  71. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/account_settings.py +0 -0
  72. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/accounts.py +0 -0
  73. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/ad_accounts.py +0 -0
  74. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/ad_audiences.py +0 -0
  75. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/ad_creatives.py +0 -0
  76. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/ad_insights.py +0 -0
  77. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/ad_targeting.py +0 -0
  78. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/ads.py +0 -0
  79. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/analytics.py +0 -0
  80. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/api_keys.py +0 -0
  81. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/broadcasts.py +0 -0
  82. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/calls.py +0 -0
  83. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/comment_automations.py +0 -0
  84. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/comments.py +0 -0
  85. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/connect.py +0 -0
  86. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/contacts.py +0 -0
  87. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/conversions.py +0 -0
  88. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/custom_fields.py +0 -0
  89. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/discord.py +0 -0
  90. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/gmb_attributes.py +0 -0
  91. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/gmb_food_menus.py +0 -0
  92. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/gmb_location_details.py +0 -0
  93. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/gmb_media.py +0 -0
  94. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/gmb_place_actions.py +0 -0
  95. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/gmb_services.py +0 -0
  96. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/gmb_verifications.py +0 -0
  97. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/inbox.py +0 -0
  98. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/inbox_analytics.py +0 -0
  99. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/instagram.py +0 -0
  100. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/invites.py +0 -0
  101. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/lead_gen.py +0 -0
  102. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/logs.py +0 -0
  103. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/media.py +0 -0
  104. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/mentions.py +0 -0
  105. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/messages.py +0 -0
  106. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/messaging_ads.py +0 -0
  107. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/posts.py +0 -0
  108. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/profiles.py +0 -0
  109. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/queue.py +0 -0
  110. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/reach_and_frequency.py +0 -0
  111. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/reddit.py +0 -0
  112. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/reviews.py +0 -0
  113. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/sequences.py +0 -0
  114. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/sms.py +0 -0
  115. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/tools.py +0 -0
  116. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/tracking_tags.py +0 -0
  117. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/twitter_engagement.py +0 -0
  118. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/usage.py +0 -0
  119. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/users.py +0 -0
  120. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/validate.py +0 -0
  121. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/verify.py +0 -0
  122. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/voice.py +0 -0
  123. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/webhooks.py +0 -0
  124. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/whatsapp.py +0 -0
  125. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/whatsapp_calling.py +0 -0
  126. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/whatsapp_flows.py +0 -0
  127. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/whatsapp_sandbox.py +0 -0
  128. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/whatsapp_templates.py +0 -0
  129. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/_generated/workflows.py +0 -0
  130. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/accounts.py +0 -0
  131. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/ads.py +0 -0
  132. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/analytics.py +0 -0
  133. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/base.py +0 -0
  134. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/media.py +0 -0
  135. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/posts.py +0 -0
  136. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/profiles.py +0 -0
  137. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/queue.py +0 -0
  138. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/tools.py +0 -0
  139. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/resources/users.py +0 -0
  140. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/upload/__init__.py +0 -0
  141. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/upload/config.py +0 -0
  142. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/upload/direct.py +0 -0
  143. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/upload/protocols.py +0 -0
  144. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/upload/smart.py +0 -0
  145. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/upload/utils.py +0 -0
  146. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/upload/vercel/__init__.py +0 -0
  147. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/upload/vercel/client.py +0 -0
  148. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/late/upload/vercel/uploader.py +0 -0
  149. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/src/zernio/__init__.py +0 -0
  150. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/tests/__init__.py +0 -0
  151. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/tests/conftest.py +0 -0
  152. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/tests/test_client.py +0 -0
  153. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/tests/test_exhaustive.py +0 -0
  154. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/tests/test_integration.py +0 -0
  155. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/tests/test_patch_methods.py +0 -0
  156. {zernio_sdk-1.4.330 → zernio_sdk-1.4.332}/tests/test_resolve_account.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zernio-sdk
3
- Version: 1.4.330
3
+ Version: 1.4.332
4
4
  Summary: The official Python library for the Zernio API
5
5
  Project-URL: Homepage, https://zernio.com
6
6
  Project-URL: Documentation, https://docs.zernio.com
@@ -459,6 +459,7 @@ Both `from zernio import ...` and `from late import ...` work identically. The `
459
459
  | Method | Description |
460
460
  |--------|-------------|
461
461
  | `ad_campaigns.list_ad_campaigns()` | List campaigns |
462
+ | `ad_campaigns.list_ad_keywords()` | List Search keywords |
462
463
  | `ad_campaigns.list_ads()` | List ads |
463
464
  | `ad_campaigns.bulk_update_ad_campaign_status()` | Pause or resume many campaigns |
464
465
  | `ad_campaigns.create_ad_campaign()` | Create a standalone campaign |
@@ -406,6 +406,7 @@ Both `from zernio import ...` and `from late import ...` work identically. The `
406
406
  | Method | Description |
407
407
  |--------|-------------|
408
408
  | `ad_campaigns.list_ad_campaigns()` | List campaigns |
409
+ | `ad_campaigns.list_ad_keywords()` | List Search keywords |
409
410
  | `ad_campaigns.list_ads()` | List ads |
410
411
  | `ad_campaigns.bulk_update_ad_campaign_status()` | Pause or resume many campaigns |
411
412
  | `ad_campaigns.create_ad_campaign()` | Create a standalone campaign |
@@ -27899,6 +27899,17 @@ paths:
27899
27899
  connect WhatsApp (400 when combined with
27900
27900
  connectWhatsapp:true), and wantsSms:true requires an
27901
27901
  SMS-capable type.
27902
+ areaCode:
27903
+ type: string
27904
+ pattern: '^\d{1,4}$'
27905
+ description: >
27906
+ Area code (national destination code, e.g. 11 for Sao
27907
+ Paulo) the number must be in. Hard constraint: when the
27908
+ area has no deliverable inventory the purchase fails with
27909
+ 409 code AREA_CODE_UNAVAILABLE instead of assigning a
27910
+ number from another area, and later replacements stay in
27911
+ this area too. Omit for any area. Get live options from
27912
+ GET /v1/phone-numbers/availability (areaOptions).
27902
27913
  connectWhatsapp:
27903
27914
  type: boolean
27904
27915
  default: true
@@ -27990,16 +28001,18 @@ paths:
27990
28001
  '403': { description: A paid plan is required }
27991
28002
  '409':
27992
28003
  description: >
27993
- Duplicate-purchase protection: another number was purchased for
27994
- this user within the last 10 minutes. Retry with allowMultiple:
27995
- true to confirm the additional purchase is intentional.
28004
+ Either duplicate-purchase protection (code PURCHASE_VELOCITY:
28005
+ another number was purchased within the last 10 minutes; retry
28006
+ with allowMultiple: true to confirm), or the requested areaCode
28007
+ has no deliverable inventory right now (code
28008
+ AREA_CODE_UNAVAILABLE: pick another area or omit areaCode).
27996
28009
  content:
27997
28010
  application/json:
27998
28011
  schema:
27999
28012
  type: object
28000
28013
  properties:
28001
28014
  error: { type: string }
28002
- code: { type: string, enum: [PURCHASE_VELOCITY] }
28015
+ code: { type: string, enum: [PURCHASE_VELOCITY, AREA_CODE_UNAVAILABLE] }
28003
28016
  '202':
28004
28017
  description: Country requires end-user KYC before the number can be ordered.
28005
28018
  content:
@@ -28132,6 +28145,7 @@ paths:
28132
28145
  parameters:
28133
28146
  - { name: country, in: query, required: true, schema: { type: string }, description: ISO-2 country code. }
28134
28147
  - { name: numberType, in: query, required: false, schema: { type: string, enum: [local, mobile, national, toll_free] }, description: "Check a specific offered type (stock and address constraints are per type). Omitted = the country's default type." }
28148
+ - { name: sms, in: query, required: false, schema: { type: boolean }, description: 'Pass true when the buyer wants SMS: availability, areas, and areaOptions then describe the SMS-capable pool (an SMS purchase orders from it), not the wider voice-only pool.' }
28135
28149
  responses:
28136
28150
  '200':
28137
28151
  description: Availability + address constraint.
@@ -28148,6 +28162,20 @@ paths:
28148
28162
  type: array
28149
28163
  description: For `geo` only — the area(s) the registered address must be in.
28150
28164
  items: { type: string }
28165
+ areaOptions:
28166
+ type: array
28167
+ description: >
28168
+ Live inventory grouped by area code, largest stock
28169
+ first. Empty when out of stock (or the area lookup
28170
+ failed). Pass a chosen `ndc` as `areaCode` on POST
28171
+ /v1/phone-numbers/purchase (or on the KYC submit for
28172
+ regulated countries) to require that area.
28173
+ items:
28174
+ type: object
28175
+ properties:
28176
+ ndc: { type: string, description: 'Area code (national destination code), e.g. "11".' }
28177
+ name: { type: string, description: 'Human-readable area name, e.g. "Sao Paulo".' }
28178
+ count: { type: integer, description: Deliverable numbers seen in this area on the latest inventory page. }
28151
28179
  '400': { description: Country not offerable }
28152
28180
  '401': { $ref: '#/components/responses/Unauthorized' }
28153
28181
 
@@ -28356,16 +28384,18 @@ paths:
28356
28384
  '403': { description: A paid plan is required }
28357
28385
  '409':
28358
28386
  description: >
28359
- Duplicate-purchase protection: another number was purchased for
28360
- this user within the last 10 minutes. Retry with allowMultiple:
28361
- true to confirm the additional purchase is intentional.
28387
+ Either duplicate-purchase protection (code PURCHASE_VELOCITY:
28388
+ another number was purchased within the last 10 minutes; retry
28389
+ with allowMultiple: true to confirm), or the requested areaCode
28390
+ has no deliverable inventory right now (code
28391
+ AREA_CODE_UNAVAILABLE: pick another area or omit areaCode).
28362
28392
  content:
28363
28393
  application/json:
28364
28394
  schema:
28365
28395
  type: object
28366
28396
  properties:
28367
28397
  error: { type: string }
28368
- code: { type: string, enum: [PURCHASE_VELOCITY] }
28398
+ code: { type: string, enum: [PURCHASE_VELOCITY, AREA_CODE_UNAVAILABLE] }
28369
28399
  '202':
28370
28400
  description: Country requires end-user KYC before the number can be ordered.
28371
28401
  content:
@@ -28481,6 +28511,7 @@ paths:
28481
28511
  parameters:
28482
28512
  - { name: country, in: query, required: true, schema: { type: string }, description: ISO-2 country code. }
28483
28513
  - { name: numberType, in: query, required: false, schema: { type: string, enum: [local, mobile, national, toll_free] }, description: "Check a specific offered type (stock and address constraints are per type). Omitted = the country's default type." }
28514
+ - { name: sms, in: query, required: false, schema: { type: boolean }, description: 'Pass true when the buyer wants SMS: availability, areas, and areaOptions then describe the SMS-capable pool (an SMS purchase orders from it), not the wider voice-only pool.' }
28484
28515
  responses:
28485
28516
  '200':
28486
28517
  description: Availability + address constraint.
@@ -28497,6 +28528,20 @@ paths:
28497
28528
  type: array
28498
28529
  description: For `geo` only — the area(s) the registered address must be in.
28499
28530
  items: { type: string }
28531
+ areaOptions:
28532
+ type: array
28533
+ description: >
28534
+ Live inventory grouped by area code, largest stock
28535
+ first. Empty when out of stock (or the area lookup
28536
+ failed). Pass a chosen `ndc` as `areaCode` on POST
28537
+ /v1/phone-numbers/purchase (or on the KYC submit for
28538
+ regulated countries) to require that area.
28539
+ items:
28540
+ type: object
28541
+ properties:
28542
+ ndc: { type: string, description: 'Area code (national destination code), e.g. "11".' }
28543
+ name: { type: string, description: 'Human-readable area name, e.g. "Sao Paulo".' }
28544
+ count: { type: integer, description: Deliverable numbers seen in this area on the latest inventory page. }
28500
28545
  '400': { description: Country not offerable }
28501
28546
  '401': { $ref: '#/components/responses/Unauthorized' }
28502
28547
 
@@ -28607,6 +28652,7 @@ paths:
28607
28652
  reuse: { type: boolean, description: Reuse a prior approved verification for this country (skips document/field collection; places the order immediately). }
28608
28653
  reuseOptionId: { type: string, description: 'Which reusable verification to use (GET reusable.options[].id). The unambiguous selection key. Omitted = the approved default. No match = 409.' }
28609
28654
  reuseFrom: { type: string, description: 'Legacy fallback for `reuseOptionId`: the source phone number (GET reusable.options[].fromPhoneNumber). Ambiguous when a number labels two verifications — prefer `reuseOptionId`. Omitted = the approved default. No match = 409.' }
28655
+ areaCode: { type: string, pattern: '^\d{1,4}$', description: 'Area code (NDC) the number must be in. Hard constraint: an empty area pool fails with 409 code AREA_CODE_UNAVAILABLE instead of ordering from another area. Omit for any area. Options come from GET /v1/phone-numbers/availability (areaOptions); the purchase 202 kycUrl echoes the areaCode picked at purchase time so it can be passed here.' }
28610
28656
  endUserFirstName: { type: string, description: End user's legal first name. Required when the country has an action/ID-verification (Onfido) requirement. }
28611
28657
  endUserLastName: { type: string, description: End user's legal last name. Same condition as endUserFirstName. }
28612
28658
  values:
@@ -28668,7 +28714,7 @@ paths:
28668
28714
  phoneNumber: { type: string }
28669
28715
  country: { type: string }
28670
28716
  '400': { description: "Validation error (e.g. address not in-country, file too large)" }
28671
- '409': { description: reuse requested but no prior approved verification exists for this country }
28717
+ '409': { description: 'Either reuse was requested but no prior approved verification exists for this country, or the requested areaCode has no deliverable inventory right now (code: area_code_unavailable; pick another area and resubmit).' }
28672
28718
  '401': { $ref: '#/components/responses/Unauthorized' }
28673
28719
 
28674
28720
  /v1/phone-numbers/kyc/document/{documentId}:
@@ -28831,6 +28877,7 @@ paths:
28831
28877
  properties:
28832
28878
  profileId: { type: string }
28833
28879
  country: { type: string, minLength: 2, maxLength: 2, description: ISO 3166-1 alpha-2 country code (must be a regulated/KYC country). }
28880
+ areaCode: { type: string, pattern: '^\d{1,4}$', description: 'Area code (NDC) the eventual number must be in. Hard constraint carried by the link; the end customer filling the form makes no area choice. Options come from GET /v1/phone-numbers/availability (areaOptions).' }
28834
28881
  branding:
28835
28882
  type: object
28836
28883
  description: Optional white-label of the hosted page the end customer sees.
@@ -29577,6 +29624,7 @@ paths:
29577
29624
  reuse: { type: boolean, description: Reuse a prior approved verification for this country (skips document/field collection; places the order immediately). }
29578
29625
  reuseOptionId: { type: string, description: 'Which reusable verification to use (GET reusable.options[].id). The unambiguous selection key. Omitted = the approved default. No match = 409.' }
29579
29626
  reuseFrom: { type: string, description: 'Legacy fallback for `reuseOptionId`: the source phone number (GET reusable.options[].fromPhoneNumber). Ambiguous when a number labels two verifications — prefer `reuseOptionId`. Omitted = the approved default. No match = 409.' }
29627
+ areaCode: { type: string, pattern: '^\d{1,4}$', description: 'Area code (NDC) the number must be in. Hard constraint: an empty area pool fails with 409 code AREA_CODE_UNAVAILABLE instead of ordering from another area. Omit for any area. Options come from GET /v1/phone-numbers/availability (areaOptions); the purchase 202 kycUrl echoes the areaCode picked at purchase time so it can be passed here.' }
29580
29628
  endUserFirstName: { type: string, description: End user's legal first name. Required when the country has an action/ID-verification (Onfido) requirement. }
29581
29629
  endUserLastName: { type: string, description: End user's legal last name. Same condition as endUserFirstName. }
29582
29630
  values:
@@ -29638,7 +29686,7 @@ paths:
29638
29686
  phoneNumber: { type: string }
29639
29687
  country: { type: string }
29640
29688
  '400': { description: "Validation error (e.g. address not in-country, file too large)" }
29641
- '409': { description: reuse requested but no prior approved verification exists for this country }
29689
+ '409': { description: 'Either reuse was requested but no prior approved verification exists for this country, or the requested areaCode has no deliverable inventory right now (code: area_code_unavailable; pick another area and resubmit).' }
29642
29690
  '401': { $ref: '#/components/responses/Unauthorized' }
29643
29691
 
29644
29692
  /v1/whatsapp/phone-numbers/kyc/upload-document:
@@ -29785,6 +29833,7 @@ paths:
29785
29833
  properties:
29786
29834
  profileId: { type: string }
29787
29835
  country: { type: string, minLength: 2, maxLength: 2, description: ISO 3166-1 alpha-2 country code (must be a regulated/KYC country). }
29836
+ areaCode: { type: string, pattern: '^\d{1,4}$', description: 'Area code (NDC) the eventual number must be in. Hard constraint carried by the link; the end customer filling the form makes no area choice. Options come from GET /v1/phone-numbers/availability (areaOptions).' }
29788
29837
  branding:
29789
29838
  type: object
29790
29839
  description: Optional white-label of the hosted page the end customer sees.
@@ -33662,6 +33711,67 @@ paths:
33662
33711
  '403':
33663
33712
  description: Ads access required. Legacy plans need the Ads add-on; included by default on usage-based plans.
33664
33713
 
33714
+ /v1/ads/keywords:
33715
+ get:
33716
+ operationId: listAdKeywords
33717
+ tags: ["Ad Campaigns"]
33718
+ x-platforms: ["google"]
33719
+ summary: List Search keywords
33720
+ description: |
33721
+ Returns the Google Search keyword criteria (positive and negative) synced from
33722
+ connected Google Ads accounts, one row per ad-group keyword. Populated by the
33723
+ periodic ads discovery sweep (roughly every 3 hours per account), so keywords
33724
+ added on Google appear with that delay. Campaign-level negative keywords are
33725
+ not included; only ad-group-level criteria are.
33726
+ security:
33727
+ - bearerAuth: []
33728
+ parameters:
33729
+ - $ref: '#/components/parameters/PageParam'
33730
+ - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 500, default: 50 } }
33731
+ - { name: accountId, in: query, schema: { type: string }, description: Social account ID }
33732
+ - { name: adAccountId, in: query, schema: { type: string }, description: 'Platform ad account ID (Google customer ID). Mirrors the same filter on /v1/ads.' }
33733
+ - { name: profileId, in: query, schema: { type: string }, description: Profile ID }
33734
+ - { name: campaignId, in: query, schema: { type: string }, description: Platform campaign ID }
33735
+ - { name: adSetId, in: query, schema: { type: string }, description: 'Platform ad group ID (Google ad group)' }
33736
+ - { name: status, in: query, schema: { type: string, enum: [active, paused] }, description: Keyword criterion status }
33737
+ - { name: matchType, in: query, schema: { type: string, enum: [exact, phrase, broad, unknown] } }
33738
+ - { name: negative, in: query, schema: { type: boolean }, description: 'true = negative keywords only, false = positive only. Omit for both.' }
33739
+ - { name: search, in: query, schema: { type: string, maxLength: 200 }, description: 'Case-insensitive substring match on the keyword text' }
33740
+ responses:
33741
+ '200':
33742
+ description: Paginated keywords
33743
+ content:
33744
+ application/json:
33745
+ schema:
33746
+ type: object
33747
+ properties:
33748
+ keywords:
33749
+ type: array
33750
+ items:
33751
+ type: object
33752
+ properties:
33753
+ id: { type: string }
33754
+ accountId: { type: string, description: Social account ID owning the sync }
33755
+ profileId: { type: string }
33756
+ platform: { type: string, enum: [google] }
33757
+ adAccountId: { type: string, description: Google customer ID }
33758
+ campaignId: { type: string }
33759
+ campaignName: { type: [string, "null"] }
33760
+ campaignStatus: { type: [string, "null"] }
33761
+ adSetId: { type: string, description: Google ad group ID }
33762
+ adSetName: { type: [string, "null"] }
33763
+ adSetStatus: { type: [string, "null"] }
33764
+ keyword: { type: string }
33765
+ matchType: { type: string, enum: [exact, phrase, broad, unknown] }
33766
+ status: { type: string, enum: [active, paused] }
33767
+ negative: { type: boolean }
33768
+ syncedAt: { type: [string, "null"], format: date-time }
33769
+ pagination: { $ref: '#/components/schemas/Pagination' }
33770
+ '400': { $ref: '#/components/responses/BadRequest' }
33771
+ '401': { $ref: '#/components/responses/Unauthorized' }
33772
+ '403':
33773
+ description: Ads access required. Legacy plans need the Ads add-on; included by default on usage-based plans.
33774
+
33665
33775
  /v1/ads/campaigns:
33666
33776
  get:
33667
33777
  operationId: listAdCampaigns
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "zernio-sdk"
3
- version = "1.4.330"
3
+ version = "1.4.332"
4
4
  description = "The official Python library for the Zernio API"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -42,7 +42,7 @@ from .enums import (
42
42
  Visibility,
43
43
  )
44
44
 
45
- __version__ = "1.4.330"
45
+ __version__ = "1.4.332"
46
46
 
47
47
  __all__ = [
48
48
  # Client
@@ -1777,6 +1777,60 @@ def register_generated_tools(mcp, _get_client):
1777
1777
  except Exception as e:
1778
1778
  return f"Error: {e}"
1779
1779
 
1780
+ @mcp.tool(
1781
+ annotations=ToolAnnotations(
1782
+ title="List Search keywords",
1783
+ readOnlyHint=True,
1784
+ destructiveHint=False,
1785
+ openWorldHint=False,
1786
+ )
1787
+ )
1788
+ def ad_campaigns_list_ad_keywords(
1789
+ page: int = 1,
1790
+ limit: int = 50,
1791
+ account_id: str | None = None,
1792
+ ad_account_id: str | None = None,
1793
+ profile_id: str | None = None,
1794
+ campaign_id: str | None = None,
1795
+ ad_set_id: str | None = None,
1796
+ status: str | None = None,
1797
+ match_type: str | None = None,
1798
+ negative: bool | None = None,
1799
+ search: str | None = None,
1800
+ ) -> str:
1801
+ """List Search keywords
1802
+
1803
+ Args:
1804
+ page: Page number
1805
+ limit
1806
+ account_id: Social account ID
1807
+ ad_account_id: Platform ad account ID (Google customer ID). Mirrors the same filter on /v1/ads.
1808
+ profile_id: Profile ID
1809
+ campaign_id: Platform campaign ID
1810
+ ad_set_id: Platform ad group ID (Google ad group)
1811
+ status: Keyword criterion status
1812
+ match_type
1813
+ negative: true = negative keywords only, false = positive only. Omit for both.
1814
+ search: Case-insensitive substring match on the keyword text"""
1815
+ client = _get_client()
1816
+ try:
1817
+ response = client.ad_campaigns.list_ad_keywords(
1818
+ page=page,
1819
+ limit=limit,
1820
+ account_id=account_id,
1821
+ ad_account_id=ad_account_id,
1822
+ profile_id=profile_id,
1823
+ campaign_id=campaign_id,
1824
+ ad_set_id=ad_set_id,
1825
+ status=status,
1826
+ match_type=match_type,
1827
+ negative=negative,
1828
+ search=search,
1829
+ )
1830
+ return _format_response(response)
1831
+ except Exception as e:
1832
+ return f"Error: {e}"
1833
+
1780
1834
  @mcp.tool(
1781
1835
  annotations=ToolAnnotations(
1782
1836
  title="List campaigns",
@@ -10187,6 +10241,7 @@ def register_generated_tools(mcp, _get_client):
10187
10241
  profile_id: str,
10188
10242
  country: str = "US",
10189
10243
  number_type: str | None = None,
10244
+ area_code: str | None = None,
10190
10245
  connect_whatsapp: bool = True,
10191
10246
  wants_sms: bool = False,
10192
10247
  wants_whatsapp: bool = False,
@@ -10199,6 +10254,7 @@ def register_generated_tools(mcp, _get_client):
10199
10254
  profile_id: Profile to associate the number with (required)
10200
10255
  country: ISO 3166-1 alpha-2 country for the number (default US). International numbers require usage-based billing. Tier 3/4 countries return 202 { status: "kyc_required", kycUrl } — the customer must complete KYC at that URL before the number is ordered. See GET /v1/phone-numbers/countries.
10201
10256
  number_type: Which of the country's offered number types to order (see `types[]` on GET /v1/phone-numbers/countries). Omitted = the country's default type, which is always the WhatsApp-safe choice. Capabilities, price, and KYC requirements are per (country, type): toll_free can never connect WhatsApp (400 when combined with connectWhatsapp:true), and wantsSms:true requires an SMS-capable type.
10257
+ area_code: Area code (national destination code, e.g. 11 for Sao Paulo) the number must be in. Hard constraint: when the area has no deliverable inventory the purchase fails with 409 code AREA_CODE_UNAVAILABLE instead of assigning a number from another area, and later replacements stay in this area too. Omit for any area. Get live options from GET /v1/phone-numbers/availability (areaOptions).
10202
10258
  connect_whatsapp: A phone number is the unit; WhatsApp is one optional feature. Pass false to buy a STANDALONE number (Calls/SMS only): provisioning skips the Meta pre-verify/OTP steps and the number activates immediately. Omitted defaults to the WhatsApp provisioning path. WhatsApp can be connected to a standalone number later from the connect flow.
10203
10259
  wants_sms: SMS capability is per-number, not per-country. Pass true to provision from the SMS-capable inventory pool so the number can actually text (see also GET /v1/phone-numbers/available with sms=true, and smsAvailable on GET /v1/phone-numbers/countries).
10204
10260
  wants_whatsapp: Declare WhatsApp intent on a STANDALONE purchase (connectWhatsapp:false). The number still activates and bills immediately, but if WhatsApp's buy-time check rejects the assigned number, it is automatically swapped for a WhatsApp-eligible one during the purchase instead of being delivered with WhatsApp unavailable. Ignored on the WhatsApp provisioning path (connectWhatsapp omitted or true), which always delivers a WhatsApp-verified number.
@@ -10210,6 +10266,7 @@ def register_generated_tools(mcp, _get_client):
10210
10266
  profile_id=profile_id,
10211
10267
  country=country,
10212
10268
  number_type=number_type,
10269
+ area_code=area_code,
10213
10270
  connect_whatsapp=connect_whatsapp,
10214
10271
  wants_sms=wants_sms,
10215
10272
  wants_whatsapp=wants_whatsapp,
@@ -10288,17 +10345,18 @@ def register_generated_tools(mcp, _get_client):
10288
10345
  )
10289
10346
  )
10290
10347
  def phone_numbers_check_phone_number_availability(
10291
- country: str, number_type: str | None = None
10348
+ country: str, number_type: str | None = None, sms: bool | None = None
10292
10349
  ) -> str:
10293
10350
  """Check country availability
10294
10351
 
10295
10352
  Args:
10296
10353
  country: ISO-2 country code. (required)
10297
- number_type: Check a specific offered type (stock and address constraints are per type). Omitted = the country's default type."""
10354
+ number_type: Check a specific offered type (stock and address constraints are per type). Omitted = the country's default type.
10355
+ sms: Pass true when the buyer wants SMS: availability, areas, and areaOptions then describe the SMS-capable pool (an SMS purchase orders from it), not the wider voice-only pool."""
10298
10356
  client = _get_client()
10299
10357
  try:
10300
10358
  response = client.phone_numbers.check_phone_number_availability(
10301
- country=country, number_type=number_type
10359
+ country=country, number_type=number_type, sms=sms
10302
10360
  )
10303
10361
  return _format_response(response)
10304
10362
  except Exception as e:
@@ -10345,6 +10403,7 @@ def register_generated_tools(mcp, _get_client):
10345
10403
  reuse: bool | None = None,
10346
10404
  reuse_option_id: str | None = None,
10347
10405
  reuse_from: str | None = None,
10406
+ area_code: str | None = None,
10348
10407
  end_user_first_name: str | None = None,
10349
10408
  end_user_last_name: str | None = None,
10350
10409
  values: dict[str, Any] | None = None,
@@ -10361,6 +10420,7 @@ def register_generated_tools(mcp, _get_client):
10361
10420
  reuse: Reuse a prior approved verification for this country (skips document/field collection; places the order immediately).
10362
10421
  reuse_option_id: Which reusable verification to use (GET reusable.options[].id). The unambiguous selection key. Omitted = the approved default. No match = 409.
10363
10422
  reuse_from: Legacy fallback for `reuseOptionId`: the source phone number (GET reusable.options[].fromPhoneNumber). Ambiguous when a number labels two verifications — prefer `reuseOptionId`. Omitted = the approved default. No match = 409.
10423
+ area_code: Area code (NDC) the number must be in. Hard constraint: an empty area pool fails with 409 code AREA_CODE_UNAVAILABLE instead of ordering from another area. Omit for any area. Options come from GET /v1/phone-numbers/availability (areaOptions); the purchase 202 kycUrl echoes the areaCode picked at purchase time so it can be passed here.
10364
10424
  end_user_first_name: End user's legal first name. Required when the country has an action/ID-verification (Onfido) requirement.
10365
10425
  end_user_last_name: End user's legal last name. Same condition as endUserFirstName.
10366
10426
  values: requirementId → textual value
@@ -10376,6 +10436,7 @@ def register_generated_tools(mcp, _get_client):
10376
10436
  reuse=reuse,
10377
10437
  reuse_option_id=reuse_option_id,
10378
10438
  reuse_from=reuse_from,
10439
+ area_code=area_code,
10379
10440
  end_user_first_name=end_user_first_name,
10380
10441
  end_user_last_name=end_user_last_name,
10381
10442
  values=values,
@@ -10472,6 +10533,7 @@ def register_generated_tools(mcp, _get_client):
10472
10533
  def phone_numbers_create_phone_number_kyc_link(
10473
10534
  profile_id: str,
10474
10535
  country: str,
10536
+ area_code: str | None = None,
10475
10537
  branding: dict[str, Any] | None = None,
10476
10538
  redirect_url: str | None = None,
10477
10539
  ) -> str:
@@ -10480,6 +10542,7 @@ def register_generated_tools(mcp, _get_client):
10480
10542
  Args:
10481
10543
  profile_id: (required)
10482
10544
  country: ISO 3166-1 alpha-2 country code (must be a regulated/KYC country). (required)
10545
+ area_code: Area code (NDC) the eventual number must be in. Hard constraint carried by the link; the end customer filling the form makes no area choice. Options come from GET /v1/phone-numbers/availability (areaOptions).
10483
10546
  branding: Optional white-label of the hosted page the end customer sees.
10484
10547
  redirect_url: Where to send the end customer's browser after a successful
10485
10548
  submit. On completion Zernio appends `kyc=submitted` and
@@ -10490,6 +10553,7 @@ def register_generated_tools(mcp, _get_client):
10490
10553
  response = client.phone_numbers.create_phone_number_kyc_link(
10491
10554
  profile_id=profile_id,
10492
10555
  country=country,
10556
+ area_code=area_code,
10493
10557
  branding=branding,
10494
10558
  redirect_url=redirect_url,
10495
10559
  )
@@ -15819,18 +15883,19 @@ def register_generated_tools(mcp, _get_client):
15819
15883
  )
15820
15884
  )
15821
15885
  def whatsapp_phone_numbers_check_whats_app_number_availability(
15822
- country: str, number_type: str | None = None
15886
+ country: str, number_type: str | None = None, sms: bool | None = None
15823
15887
  ) -> str:
15824
15888
  """Check country availability
15825
15889
 
15826
15890
  Args:
15827
15891
  country: ISO-2 country code. (required)
15828
- number_type: Check a specific offered type (stock and address constraints are per type). Omitted = the country's default type."""
15892
+ number_type: Check a specific offered type (stock and address constraints are per type). Omitted = the country's default type.
15893
+ sms: Pass true when the buyer wants SMS: availability, areas, and areaOptions then describe the SMS-capable pool (an SMS purchase orders from it), not the wider voice-only pool."""
15829
15894
  client = _get_client()
15830
15895
  try:
15831
15896
  response = (
15832
15897
  client.whatsapp_phone_numbers.check_whats_app_number_availability(
15833
- country=country, number_type=number_type
15898
+ country=country, number_type=number_type, sms=sms
15834
15899
  )
15835
15900
  )
15836
15901
  return _format_response(response)
@@ -15878,6 +15943,7 @@ def register_generated_tools(mcp, _get_client):
15878
15943
  reuse: bool | None = None,
15879
15944
  reuse_option_id: str | None = None,
15880
15945
  reuse_from: str | None = None,
15946
+ area_code: str | None = None,
15881
15947
  end_user_first_name: str | None = None,
15882
15948
  end_user_last_name: str | None = None,
15883
15949
  values: dict[str, Any] | None = None,
@@ -15894,6 +15960,7 @@ def register_generated_tools(mcp, _get_client):
15894
15960
  reuse: Reuse a prior approved verification for this country (skips document/field collection; places the order immediately).
15895
15961
  reuse_option_id: Which reusable verification to use (GET reusable.options[].id). The unambiguous selection key. Omitted = the approved default. No match = 409.
15896
15962
  reuse_from: Legacy fallback for `reuseOptionId`: the source phone number (GET reusable.options[].fromPhoneNumber). Ambiguous when a number labels two verifications — prefer `reuseOptionId`. Omitted = the approved default. No match = 409.
15963
+ area_code: Area code (NDC) the number must be in. Hard constraint: an empty area pool fails with 409 code AREA_CODE_UNAVAILABLE instead of ordering from another area. Omit for any area. Options come from GET /v1/phone-numbers/availability (areaOptions); the purchase 202 kycUrl echoes the areaCode picked at purchase time so it can be passed here.
15897
15964
  end_user_first_name: End user's legal first name. Required when the country has an action/ID-verification (Onfido) requirement.
15898
15965
  end_user_last_name: End user's legal last name. Same condition as endUserFirstName.
15899
15966
  values: requirementId → textual value
@@ -15909,6 +15976,7 @@ def register_generated_tools(mcp, _get_client):
15909
15976
  reuse=reuse,
15910
15977
  reuse_option_id=reuse_option_id,
15911
15978
  reuse_from=reuse_from,
15979
+ area_code=area_code,
15912
15980
  end_user_first_name=end_user_first_name,
15913
15981
  end_user_last_name=end_user_last_name,
15914
15982
  values=values,
@@ -15987,6 +16055,7 @@ def register_generated_tools(mcp, _get_client):
15987
16055
  def whatsapp_phone_numbers_create_whats_app_number_kyc_link(
15988
16056
  profile_id: str,
15989
16057
  country: str,
16058
+ area_code: str | None = None,
15990
16059
  branding: dict[str, Any] | None = None,
15991
16060
  redirect_url: str | None = None,
15992
16061
  ) -> str:
@@ -15995,6 +16064,7 @@ def register_generated_tools(mcp, _get_client):
15995
16064
  Args:
15996
16065
  profile_id: (required)
15997
16066
  country: ISO 3166-1 alpha-2 country code (must be a regulated/KYC country). (required)
16067
+ area_code: Area code (NDC) the eventual number must be in. Hard constraint carried by the link; the end customer filling the form makes no area choice. Options come from GET /v1/phone-numbers/availability (areaOptions).
15998
16068
  branding: Optional white-label of the hosted page the end customer sees.
15999
16069
  redirect_url: Where to send the end customer's browser after a successful
16000
16070
  submit. On completion Zernio appends `kyc=submitted` and
@@ -16005,6 +16075,7 @@ def register_generated_tools(mcp, _get_client):
16005
16075
  response = client.whatsapp_phone_numbers.create_whats_app_number_kyc_link(
16006
16076
  profile_id=profile_id,
16007
16077
  country=country,
16078
+ area_code=area_code,
16008
16079
  branding=branding,
16009
16080
  redirect_url=redirect_url,
16010
16081
  )
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: openapi.yaml
3
- # timestamp: 2026-07-24T16:38:10+00:00
3
+ # timestamp: 2026-07-27T09:31:44+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -93,6 +93,37 @@ class AdCampaignsResource:
93
93
  )
94
94
  return self._client._get("/v1/ads", params=params)
95
95
 
96
+ def list_ad_keywords(
97
+ self,
98
+ *,
99
+ page: int | None = 1,
100
+ limit: int | None = 50,
101
+ account_id: str | None = None,
102
+ ad_account_id: str | None = None,
103
+ profile_id: str | None = None,
104
+ campaign_id: str | None = None,
105
+ ad_set_id: str | None = None,
106
+ status: str | None = None,
107
+ match_type: str | None = None,
108
+ negative: bool | None = None,
109
+ search: str | None = None,
110
+ ) -> dict[str, Any]:
111
+ """List Search keywords"""
112
+ params = self._build_params(
113
+ page=page,
114
+ limit=limit,
115
+ account_id=account_id,
116
+ ad_account_id=ad_account_id,
117
+ profile_id=profile_id,
118
+ campaign_id=campaign_id,
119
+ ad_set_id=ad_set_id,
120
+ status=status,
121
+ match_type=match_type,
122
+ negative=negative,
123
+ search=search,
124
+ )
125
+ return self._client._get("/v1/ads/keywords", params=params)
126
+
96
127
  def list_ad_campaigns(
97
128
  self,
98
129
  *,
@@ -670,6 +701,37 @@ class AdCampaignsResource:
670
701
  )
671
702
  return await self._client._aget("/v1/ads", params=params)
672
703
 
704
+ async def alist_ad_keywords(
705
+ self,
706
+ *,
707
+ page: int | None = 1,
708
+ limit: int | None = 50,
709
+ account_id: str | None = None,
710
+ ad_account_id: str | None = None,
711
+ profile_id: str | None = None,
712
+ campaign_id: str | None = None,
713
+ ad_set_id: str | None = None,
714
+ status: str | None = None,
715
+ match_type: str | None = None,
716
+ negative: bool | None = None,
717
+ search: str | None = None,
718
+ ) -> dict[str, Any]:
719
+ """List Search keywords (async)"""
720
+ params = self._build_params(
721
+ page=page,
722
+ limit=limit,
723
+ account_id=account_id,
724
+ ad_account_id=ad_account_id,
725
+ profile_id=profile_id,
726
+ campaign_id=campaign_id,
727
+ ad_set_id=ad_set_id,
728
+ status=status,
729
+ match_type=match_type,
730
+ negative=negative,
731
+ search=search,
732
+ )
733
+ return await self._client._aget("/v1/ads/keywords", params=params)
734
+
673
735
  async def alist_ad_campaigns(
674
736
  self,
675
737
  *,