zernio-sdk 0.0.808 → 0.0.810

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 222fdceabd0d35e142c14cd6ed9553cc8c96c4a7d7abb5a5e30035080470ed94
4
- data.tar.gz: 4de4dff7efe390db62c20a3bec5515b94d8428b84d196f69c79955a782815d61
3
+ metadata.gz: efee100b19cee0588302d4a9f5c0fc7e1de393694cfdff7b9c718d4cb34c19d5
4
+ data.tar.gz: 33c0cebb565cb9ce81e7d14f65abe09a2e26049b757a487e81d92e94bda9d213
5
5
  SHA512:
6
- metadata.gz: 10f0940fd7f8cc10520c37508ba2252e6dc8857042e28959cc4265e72c4febffde9f90f9ffaf5145e28c24bd2680e71added962cabb911e0a4d21a1ea6063a50
7
- data.tar.gz: e359a375fa434cf95342c24d9f985d8a08d948cd00aa29ccfc0b56de00088923f9299798d4e306f116a056799f6239a1074bb87b222ee61e60b16bd5ce8aff2d
6
+ metadata.gz: fe2f79eddbe62681e4143cdc567bebc0b470773eb4e4dab23549a16d4e4fff61ed4938c35635c8aafa9e28c09971044685b0cc49c68a4fe47a0ad4d2e05cdcce
7
+ data.tar.gz: d1e2f6ee12c5a05375f21997ae41b7d2030371a48fa925d077043be223fe4e0a2dadf3a02fe6ca7205e93a898c74a3daa1d03aba59b679fcd08d0417661919f5
data/docs/ConnectApi.md CHANGED
@@ -343,7 +343,7 @@ end
343
343
 
344
344
  Connect ads for a platform
345
345
 
346
- Unified ads connection endpoint. Creates a dedicated ads SocialAccount for the specified platform. Same-token platforms (facebook, instagram, linkedin, pinterest): Creates an ads SocialAccount (metaads, linkedinads, pinterestads) with a copied OAuth token from the parent posting account. If the ads account already exists, returns alreadyConnected: true. No extra OAuth needed. Separate-token platforms (tiktok, twitter): Starts the platform-specific marketing API OAuth flow and creates an ads SocialAccount (tiktokads, xads) with its own token. If the ads account already exists, returns alreadyConnected: true. - tiktok: accountId is OPTIONAL. With accountId, the new tiktokads account links to that posting account (parentAccountId set) — Spark Ads + standalone ads using the posting TT_USER identity become available. Without accountId, ads-only mode kicks in: the new tiktokads account has parentAccountId=null and standalone ads use a synthetic CUSTOMIZED_USER (\"Brand Identity\"); Spark Ads are unavailable because TikTok requires a posting account for them. The Brand Identity is configured separately via PATCH /v1/connect/tiktok-ads (or inline on POST /v1/ads/create via the brandIdentity field). - twitter (X Ads): accountId is REQUIRED. There's no ads-only mode — tweets need to be authored by a real X user. Standalone platforms (googleads): Starts the Google Ads OAuth flow and creates a standalone ads SocialAccount (googleads) with no parent. If the account already exists, returns alreadyConnected: true. Ads accounts appear as regular SocialAccount documents with ads platform values (e.g., metaads, tiktokads) in GET /v1/accounts.
346
+ Unified ads connection endpoint. Creates a dedicated ads SocialAccount for the specified platform. Same-token platforms (facebook, instagram, linkedin, pinterest): the ads SocialAccount (metaads, linkedinads, pinterestads) reuses the OAuth token of the parent posting account, but only when an active parent exists and, for facebook and instagram, its stored token carries ads_management and ads_read (linkedin and pinterest need no extra scope). In that case no extra OAuth happens and the response is alreadyConnected: true. When no such parent exists, or the scopes are missing, the endpoint returns an authUrl and a full OAuth round trip is required. When a parent exists but carries no token usable for ad accounts, the call fails with 400 RECONNECT_REQUIRED. Independently of the branch, the call can return 403 ADS_ADDON_REQUIRED without the ads add-on and 402 PAYMENT_REQUIRED when the billing gate is closed. Meta Ads prerequisite: connecting Meta Ads (via facebook or instagram) requires a Facebook Page. Not because the ad account is read through a Page, but because both parent posting accounts are: the facebook flow only offers Pages you manage, and the instagram flow with loginMethod=facebook_login only offers Instagram accounts linked to one of those Pages. Without a Page there is no parent account to inherit a token from. A user who manages no Facebook Page cannot complete this connection, and the facebook flow ends with error=no_facebook_pages. Separate-token platforms (tiktok, twitter): Starts the platform-specific marketing API OAuth flow and creates an ads SocialAccount (tiktokads, xads) with its own token. If the ads account already exists, returns alreadyConnected: true. - tiktok: accountId is OPTIONAL. With accountId, the new tiktokads account links to that posting account (parentAccountId set) — Spark Ads + standalone ads using the posting TT_USER identity become available. Without accountId, ads-only mode kicks in: the new tiktokads account has parentAccountId=null and standalone ads use a synthetic CUSTOMIZED_USER (\"Brand Identity\"); Spark Ads are unavailable because TikTok requires a posting account for them. The Brand Identity is configured separately via PATCH /v1/connect/tiktok-ads (or inline on POST /v1/ads/create via the brandIdentity field). - twitter (X Ads): accountId is REQUIRED. There's no ads-only mode — tweets need to be authored by a real X user. Standalone platforms (googleads): Starts the Google Ads OAuth flow and creates a standalone ads SocialAccount (googleads) with no parent. If the account already exists, returns alreadyConnected: true. Ads accounts appear as regular SocialAccount documents with ads platform values (e.g., metaads, tiktokads) in GET /v1/accounts.
347
347
 
348
348
  ### Examples
349
349
 
@@ -357,11 +357,11 @@ Zernio.configure do |config|
357
357
  end
358
358
 
359
359
  api_instance = Zernio::ConnectApi.new
360
- platform = 'facebook' # String | Platform to connect ads for. Only platforms with ads support are accepted.
360
+ platform = 'facebook' # String | Platform to connect ads for. Only platforms with ads support are accepted. `instagram` requires an Instagram account connected with loginMethod=facebook_login whose token carries ads_management and ads_read. With an account connected through the default instagram_login flow no ads account can be created; do not use this value for those accounts.
361
361
  profile_id = 'profile_id_example' # String | Your Zernio profile ID
362
362
  opts = {
363
363
  account_id: 'account_id_example', # String | Existing SocialAccount ID. Required for `twitter` (X Ads). Optional for `tiktok` — omit to enter ads-only mode (no TikTok posting account linked; ad creation uses a Brand Identity instead of a TT_USER). Ignored for same-token (`facebook`, `instagram`, `linkedin`, `pinterest`) and standalone (`googleads`) platforms.
364
- redirect_url: 'redirect_url_example', # String | Custom URL the browser is sent to once the OAuth flow finishes. Honored on every ads platform, including the separate-token (`tiktok`, `twitter`) and standalone (`googleads`) flows. Accepts an http(s) URL, a custom app scheme for mobile deeplinks (e.g. myapp://callback), or a relative path. On success `tiktok`, `twitter` and `googleads` land on the URL unchanged, while the same-token platforms (`facebook`, `instagram`, `linkedin`, `pinterest`) append `connected`, `profileId`, `accountId`, `username` and, on API-key calls, `connect_token`. On failure every platform appends error details, starting with `error` and `platform`. When omitted, the browser lands on the Zernio dashboard.
364
+ redirect_url: 'redirect_url_example', # String | Custom URL the browser is sent to once the OAuth flow finishes. Honored on every ads platform, including the separate-token (`tiktok`, `twitter`) and standalone (`googleads`) flows. Accepts an http(s) URL, a custom app scheme for mobile deeplinks (e.g. myapp://callback), or a relative path. On success `tiktok`, `twitter` and `googleads` land on the URL unchanged, while the same-token platforms (`facebook`, `instagram`, `linkedin`, `pinterest`) append `connected`, `profileId`, `accountId`, `username` and, on API-key calls, `connect_token`. On failure the same error contract applies as on GET /v1/connect/{platform}: `error` and `platform` are always appended, other params are optional, and the value list there is not exhaustive. Note that on the tiktok, twitter and googleads flows `platform` carries the ads platform id (`tiktokads`, `xads`, `googleads`), not the value used in the request path. When omitted, the browser lands on the Zernio dashboard.
365
365
  headless: true, # Boolean | Enable headless mode (same-token platforms only)
366
366
  force: true, # Boolean | Force a fresh OAuth even when an account already exists. Normally the endpoint returns `alreadyConnected: true` whenever a connected account is found, keying off its active state rather than token liveness. Set `force=true` to bypass that and always receivean `authUrl`. Completing the returned OAuth refreshes the stored token on the existing posting and ads accounts in place.
367
367
  ad_account_id: 'act_1330190928038136', # String | Scope ad sync to a single platform ad account. Without this param, sync covers every ad account the connected token can see. Supported on `facebook`/`instagram` (Meta, `act_<digits>`), `linkedin` (bare numeric sponsored-account id), `googleads` (bare customer id digits) and `twitter` (X Ads, base36 account id). `tiktok` scopes advertisers at OAuth and `pinterest` has no ads discovery, so both ignore it. Meta ids are additionally validated against the connected token; unreachable IDs return 400. Setting a scope also removes already synced ads from de-scoped ad accounts. For multiple accounts use `adAccountIds` instead.
@@ -399,10 +399,10 @@ end
399
399
 
400
400
  | Name | Type | Description | Notes |
401
401
  | ---- | ---- | ----------- | ----- |
402
- | **platform** | **String** | Platform to connect ads for. Only platforms with ads support are accepted. | |
402
+ | **platform** | **String** | Platform to connect ads for. Only platforms with ads support are accepted. &#x60;instagram&#x60; requires an Instagram account connected with loginMethod&#x3D;facebook_login whose token carries ads_management and ads_read. With an account connected through the default instagram_login flow no ads account can be created; do not use this value for those accounts. | |
403
403
  | **profile_id** | **String** | Your Zernio profile ID | |
404
404
  | **account_id** | **String** | Existing SocialAccount ID. Required for &#x60;twitter&#x60; (X Ads). Optional for &#x60;tiktok&#x60; — omit to enter ads-only mode (no TikTok posting account linked; ad creation uses a Brand Identity instead of a TT_USER). Ignored for same-token (&#x60;facebook&#x60;, &#x60;instagram&#x60;, &#x60;linkedin&#x60;, &#x60;pinterest&#x60;) and standalone (&#x60;googleads&#x60;) platforms. | [optional] |
405
- | **redirect_url** | **String** | Custom URL the browser is sent to once the OAuth flow finishes. Honored on every ads platform, including the separate-token (&#x60;tiktok&#x60;, &#x60;twitter&#x60;) and standalone (&#x60;googleads&#x60;) flows. Accepts an http(s) URL, a custom app scheme for mobile deeplinks (e.g. myapp://callback), or a relative path. On success &#x60;tiktok&#x60;, &#x60;twitter&#x60; and &#x60;googleads&#x60; land on the URL unchanged, while the same-token platforms (&#x60;facebook&#x60;, &#x60;instagram&#x60;, &#x60;linkedin&#x60;, &#x60;pinterest&#x60;) append &#x60;connected&#x60;, &#x60;profileId&#x60;, &#x60;accountId&#x60;, &#x60;username&#x60; and, on API-key calls, &#x60;connect_token&#x60;. On failure every platform appends error details, starting with &#x60;error&#x60; and &#x60;platform&#x60;. When omitted, the browser lands on the Zernio dashboard. | [optional] |
405
+ | **redirect_url** | **String** | Custom URL the browser is sent to once the OAuth flow finishes. Honored on every ads platform, including the separate-token (&#x60;tiktok&#x60;, &#x60;twitter&#x60;) and standalone (&#x60;googleads&#x60;) flows. Accepts an http(s) URL, a custom app scheme for mobile deeplinks (e.g. myapp://callback), or a relative path. On success &#x60;tiktok&#x60;, &#x60;twitter&#x60; and &#x60;googleads&#x60; land on the URL unchanged, while the same-token platforms (&#x60;facebook&#x60;, &#x60;instagram&#x60;, &#x60;linkedin&#x60;, &#x60;pinterest&#x60;) append &#x60;connected&#x60;, &#x60;profileId&#x60;, &#x60;accountId&#x60;, &#x60;username&#x60; and, on API-key calls, &#x60;connect_token&#x60;. On failure the same error contract applies as on GET /v1/connect/{platform}: &#x60;error&#x60; and &#x60;platform&#x60; are always appended, other params are optional, and the value list there is not exhaustive. Note that on the tiktok, twitter and googleads flows &#x60;platform&#x60; carries the ads platform id (&#x60;tiktokads&#x60;, &#x60;xads&#x60;, &#x60;googleads&#x60;), not the value used in the request path. When omitted, the browser lands on the Zernio dashboard. | [optional] |
406
406
  | **headless** | **Boolean** | Enable headless mode (same-token platforms only) | [optional][default to false] |
407
407
  | **force** | **Boolean** | Force a fresh OAuth even when an account already exists. Normally the endpoint returns &#x60;alreadyConnected: true&#x60; whenever a connected account is found, keying off its active state rather than token liveness. Set &#x60;force&#x3D;true&#x60; to bypass that and always receivean &#x60;authUrl&#x60;. Completing the returned OAuth refreshes the stored token on the existing posting and ads accounts in place. | [optional][default to false] |
408
408
  | **ad_account_id** | **String** | Scope ad sync to a single platform ad account. Without this param, sync covers every ad account the connected token can see. Supported on &#x60;facebook&#x60;/&#x60;instagram&#x60; (Meta, &#x60;act_&lt;digits&gt;&#x60;), &#x60;linkedin&#x60; (bare numeric sponsored-account id), &#x60;googleads&#x60; (bare customer id digits) and &#x60;twitter&#x60; (X Ads, base36 account id). &#x60;tiktok&#x60; scopes advertisers at OAuth and &#x60;pinterest&#x60; has no ads discovery, so both ignore it. Meta ids are additionally validated against the connected token; unreachable IDs return 400. Setting a scope also removes already synced ads from de-scoped ad accounts. For multiple accounts use &#x60;adAccountIds&#x60; instead. | [optional] |
@@ -996,7 +996,7 @@ api_instance = Zernio::ConnectApi.new
996
996
  platform = 'facebook' # String | Social media platform to connect
997
997
  profile_id = 'profile_id_example' # String | Your Zernio profile ID (get from /v1/profiles). For WhatsApp, a Zernio-provisioned number can only be connected on the profile it was provisioned to; connecting from any other profile is rejected with a 409.
998
998
  opts = {
999
- redirect_url: 'redirect_url_example', # String | Your custom redirect URL after connection completes. Accepts an http(s) URL, a custom app scheme for mobile deeplinks (e.g. myapp://callback), or a relative path. Result params are appended with the URL API, so an existing query string is preserved. Standard mode appends connected={platform}&profileId=X&accountId=Y&username=Z. Headless mode appends OAuth data params for platforms requiring selection (e.g. LinkedIn orgs, Facebook pages). If no selection is needed, the account is created directly and the redirect includes accountId.
999
+ redirect_url: 'redirect_url_example', # String | Your custom redirect URL after connection completes. Accepts an http(s) URL, a custom app scheme for mobile deeplinks (e.g. myapp://callback), or a relative path. Result params are appended with the URL API, so an existing query string is preserved. Standard mode appends connected={platform}&profileId=X&accountId=Y&username=Z. Headless mode appends OAuth data params for platforms requiring selection (e.g. LinkedIn orgs, Facebook pages). If no selection is needed, the account is created directly and the redirect includes accountId. On failure, the browser is sent to the same redirect_url with `error` and `platform` appended. `error` and `platform` are always present. `error_message`, `is_user_fixable`, `reason` and `dashboard_url` are conditional and must be treated as optional. This list is NOT exhaustive and new values may be added at any time. Treat an unrecognized value as a generic failure rather than matching it exhaustively. Existing values are not renamed or removed without notice. OAuth and callback: oauth_denied, invalid_callback, invalid_state, unsupported_platform, connection_failed, internal_error, token_exchange_failed, byok_config_error, personal_account_not_supported, missing_google_permissions, platform_requires_destination, reconnect_account_mismatch, invalid_request Access and limits: profile_not_found, invalid_profile_id, access_denied, account_limit_exceeded, profile_limit_exceeded, payment_required Destination selection: no_facebook_pages, facebook_pages_error, no_google_locations, google_locations_error, google_permission_denied, no_snapchat_public_profiles, snapchat_profiles_error, discord_no_guild, slack_no_team WhatsApp: whatsapp_error, one_whatsapp_per_profile, whatsapp_number_already_connected, whatsapp_number_pinned_to_profile, connection_cancelled Google Ads (platform=googleads): google_ads_auth_failed, google_ads_invalid_state, google_ads_config_error, google_ads_token_failed, google_ads_quota_exhausted, google_ads_callback_error TikTok Ads (platform=tiktokads): tiktok_ads_auth_failed, tiktok_ads_invalid_state, tiktok_ads_access_denied, tiktok_ads_config_error, tiktok_ads_token_failed, tiktok_ads_account_not_found, tiktok_ads_callback_error X Ads (platform=xads): x_ads_denied, x_ads_auth_failed, x_ads_config_error, x_ads_account_not_found, x_ads_state_error, x_ads_token_failed, x_ads_token_missing, x_ads_callback_error Shopify (platform=shopify): shopify_auth_failed, shopify_config_error, shopify_invalid_state, shopify_invalid_hmac, shopify_invalid_shop, shopify_missing_scopes, shopify_callback_error 1. On this endpoint every upstream OAuth error is collapsed into `oauth_denied`. The provider's own value (for example Meta's `access_denied`) is not forwarded. The dedicated ads flows below are different: they use their own denial slugs and `google_ads_auth_failed` and `tiktok_ads_auth_failed` may carry the provider's raw error string in `error_message`. 2. On the tiktok and twitter ads flows `platform` carries the ads platform id (`tiktokads`, `xads`), not the value used in the request path. The googleads and shopify flows report `googleads` and `shopify`.
1000
1000
  headless: true, # Boolean | When true, the user is redirected to your redirect_url with raw OAuth data (code, state) instead of Zernio's default account selection UI. Use this to build a custom connect experience.
1001
1001
  login_method: 'instagram_login', # String | Instagram only. Which of the two Instagram connection methods to use. Ignored for every other platform. `instagram_login` (the default, and what you get if you omit this): the Instagram Login dialog. The user authorizes their Instagram professional account directly, no Facebook Page required. `facebook_login`: the Facebook Login dialog, i.e. \"Instagram API with Facebook Login\". The user authorizes a Facebook Page that has a linked Instagram professional account, and every API call for that account then runs through the Page. Use this when the customer manages Instagram through a Page and expects the Facebook consent screen. Because the user has to pick which Page to connect, the callback continues at the account-selection step, `/v1/connect/instagram/select-account`. `facebook_login` supports `headless=true` like the other selection platforms: the callback redirects to your `redirect_url` with `profileId`, `tempToken`, `platform=instagram`, `step=select_account` and `connect_token`, which you pass into the select-account endpoints to finish. The default `instagram_login` has no selection step, so it connects the account directly.
1002
1002
  onboarding: 'api' # String | WhatsApp only. Ignored for every other platform. Controls which screen Meta's Embedded Signup popup shows. If omitted, the connection defaults to coexistence (same as `business_app` below), preserving existing behavior for numbers already on the WhatsApp Business app. `api`: standard Embedded Signup, showing Meta's WABA/number picker. Use this to connect a phone number already on Cloud API elsewhere. `business_app`: coexistence, i.e. 'Connect existing WhatsApp Business app' (a number shared between Cloud API and the consumer WhatsApp Business app).
@@ -1035,7 +1035,7 @@ end
1035
1035
  | ---- | ---- | ----------- | ----- |
1036
1036
  | **platform** | **String** | Social media platform to connect | |
1037
1037
  | **profile_id** | **String** | Your Zernio profile ID (get from /v1/profiles). For WhatsApp, a Zernio-provisioned number can only be connected on the profile it was provisioned to; connecting from any other profile is rejected with a 409. | |
1038
- | **redirect_url** | **String** | Your custom redirect URL after connection completes. Accepts an http(s) URL, a custom app scheme for mobile deeplinks (e.g. myapp://callback), or a relative path. Result params are appended with the URL API, so an existing query string is preserved. Standard mode appends connected&#x3D;{platform}&amp;profileId&#x3D;X&amp;accountId&#x3D;Y&amp;username&#x3D;Z. Headless mode appends OAuth data params for platforms requiring selection (e.g. LinkedIn orgs, Facebook pages). If no selection is needed, the account is created directly and the redirect includes accountId. | [optional] |
1038
+ | **redirect_url** | **String** | Your custom redirect URL after connection completes. Accepts an http(s) URL, a custom app scheme for mobile deeplinks (e.g. myapp://callback), or a relative path. Result params are appended with the URL API, so an existing query string is preserved. Standard mode appends connected&#x3D;{platform}&amp;profileId&#x3D;X&amp;accountId&#x3D;Y&amp;username&#x3D;Z. Headless mode appends OAuth data params for platforms requiring selection (e.g. LinkedIn orgs, Facebook pages). If no selection is needed, the account is created directly and the redirect includes accountId. On failure, the browser is sent to the same redirect_url with &#x60;error&#x60; and &#x60;platform&#x60; appended. &#x60;error&#x60; and &#x60;platform&#x60; are always present. &#x60;error_message&#x60;, &#x60;is_user_fixable&#x60;, &#x60;reason&#x60; and &#x60;dashboard_url&#x60; are conditional and must be treated as optional. This list is NOT exhaustive and new values may be added at any time. Treat an unrecognized value as a generic failure rather than matching it exhaustively. Existing values are not renamed or removed without notice. OAuth and callback: oauth_denied, invalid_callback, invalid_state, unsupported_platform, connection_failed, internal_error, token_exchange_failed, byok_config_error, personal_account_not_supported, missing_google_permissions, platform_requires_destination, reconnect_account_mismatch, invalid_request Access and limits: profile_not_found, invalid_profile_id, access_denied, account_limit_exceeded, profile_limit_exceeded, payment_required Destination selection: no_facebook_pages, facebook_pages_error, no_google_locations, google_locations_error, google_permission_denied, no_snapchat_public_profiles, snapchat_profiles_error, discord_no_guild, slack_no_team WhatsApp: whatsapp_error, one_whatsapp_per_profile, whatsapp_number_already_connected, whatsapp_number_pinned_to_profile, connection_cancelled Google Ads (platform&#x3D;googleads): google_ads_auth_failed, google_ads_invalid_state, google_ads_config_error, google_ads_token_failed, google_ads_quota_exhausted, google_ads_callback_error TikTok Ads (platform&#x3D;tiktokads): tiktok_ads_auth_failed, tiktok_ads_invalid_state, tiktok_ads_access_denied, tiktok_ads_config_error, tiktok_ads_token_failed, tiktok_ads_account_not_found, tiktok_ads_callback_error X Ads (platform&#x3D;xads): x_ads_denied, x_ads_auth_failed, x_ads_config_error, x_ads_account_not_found, x_ads_state_error, x_ads_token_failed, x_ads_token_missing, x_ads_callback_error Shopify (platform&#x3D;shopify): shopify_auth_failed, shopify_config_error, shopify_invalid_state, shopify_invalid_hmac, shopify_invalid_shop, shopify_missing_scopes, shopify_callback_error 1. On this endpoint every upstream OAuth error is collapsed into &#x60;oauth_denied&#x60;. The provider&#39;s own value (for example Meta&#39;s &#x60;access_denied&#x60;) is not forwarded. The dedicated ads flows below are different: they use their own denial slugs and &#x60;google_ads_auth_failed&#x60; and &#x60;tiktok_ads_auth_failed&#x60; may carry the provider&#39;s raw error string in &#x60;error_message&#x60;. 2. On the tiktok and twitter ads flows &#x60;platform&#x60; carries the ads platform id (&#x60;tiktokads&#x60;, &#x60;xads&#x60;), not the value used in the request path. The googleads and shopify flows report &#x60;googleads&#x60; and &#x60;shopify&#x60;. | [optional] |
1039
1039
  | **headless** | **Boolean** | When true, the user is redirected to your redirect_url with raw OAuth data (code, state) instead of Zernio&#39;s default account selection UI. Use this to build a custom connect experience. | [optional][default to false] |
1040
1040
  | **login_method** | **String** | Instagram only. Which of the two Instagram connection methods to use. Ignored for every other platform. &#x60;instagram_login&#x60; (the default, and what you get if you omit this): the Instagram Login dialog. The user authorizes their Instagram professional account directly, no Facebook Page required. &#x60;facebook_login&#x60;: the Facebook Login dialog, i.e. \&quot;Instagram API with Facebook Login\&quot;. The user authorizes a Facebook Page that has a linked Instagram professional account, and every API call for that account then runs through the Page. Use this when the customer manages Instagram through a Page and expects the Facebook consent screen. Because the user has to pick which Page to connect, the callback continues at the account-selection step, &#x60;/v1/connect/instagram/select-account&#x60;. &#x60;facebook_login&#x60; supports &#x60;headless&#x3D;true&#x60; like the other selection platforms: the callback redirects to your &#x60;redirect_url&#x60; with &#x60;profileId&#x60;, &#x60;tempToken&#x60;, &#x60;platform&#x3D;instagram&#x60;, &#x60;step&#x3D;select_account&#x60; and &#x60;connect_token&#x60;, which you pass into the select-account endpoints to finish. The default &#x60;instagram_login&#x60; has no selection step, so it connects the account directly. | [optional][default to &#39;instagram_login&#39;] |
1041
1041
  | **onboarding** | **String** | WhatsApp only. Ignored for every other platform. Controls which screen Meta&#39;s Embedded Signup popup shows. If omitted, the connection defaults to coexistence (same as &#x60;business_app&#x60; below), preserving existing behavior for numbers already on the WhatsApp Business app. &#x60;api&#x60;: standard Embedded Signup, showing Meta&#39;s WABA/number picker. Use this to connect a phone number already on Cloud API elsewhere. &#x60;business_app&#x60;: coexistence, i.e. &#39;Connect existing WhatsApp Business app&#39; (a number shared between Cloud API and the consumer WhatsApp Business app). | [optional] |
@@ -6,6 +6,7 @@
6
6
  | ---- | ---- | ----------- | ----- |
7
7
  | **id** | **String** | | [optional] |
8
8
  | **type** | **String** | | [optional] |
9
+ | **original_type** | **String** | Instagram and Facebook only, and present only when it differs from &#x60;type&#x60;. Meta&#39;s own type before normalization: &#x60;ig_reel&#x60; and &#x60;reel&#x60; become &#x60;video&#x60;, while &#x60;ig_post&#x60;, &#x60;post&#x60;, &#x60;ig_story&#x60; and &#x60;story_mention&#x60; become &#x60;share&#x60;. A story mention is &#x60;type: \&quot;share\&quot;&#x60; with &#x60;originalType: \&quot;story_mention\&quot;&#x60;; render on this field, since &#x60;share&#x60; alone is ambiguous. | [optional] |
9
10
  | **url** | **String** | Direct media link. On Instagram and Facebook this is a signed Meta CDN url that EXPIRES: use it now, do not store it. Persist &#x60;refreshUrl&#x60; instead. | [optional] |
10
11
  | **refresh_url** | **String** | Instagram and Facebook only. Endpoint that resolves this attachment to a working url every time, re-minting it from Meta when the stored one has expired. Safe to store and render indefinitely. | [optional] |
11
12
  | **filename** | **String** | | [optional] |
@@ -19,6 +20,7 @@ require 'zernio-sdk'
19
20
  instance = Zernio::GetInboxConversationMessages200ResponseMessagesInnerAttachmentsInner.new(
20
21
  id: null,
21
22
  type: null,
23
+ original_type: null,
22
24
  url: null,
23
25
  refresh_url: null,
24
26
  filename: null,
data/docs/MessagesApi.md CHANGED
@@ -465,7 +465,7 @@ end
465
465
 
466
466
  Resolve message attachment
467
467
 
468
- Resolve one attachment on a message to a media url that works right now. Instagram and Facebook sign DM media urls per request and expire them, so the `url` on a message is a snapshot: it works when you read the message and stops working later. This endpoint checks the stored url and, when it has gone stale, re-mints the message's media from Meta and persists it before answering. The message id never expires, so this URL is the one to store — it is returned on each attachment as `refreshUrl`. By default it responds `302` to the live media url, so it can be used directly as an `<img src>` on a browser session. API-key integrators should pass `?format=json` and read `url` off the body, since a browser cannot attach an Authorization header to an image request. Only Instagram and Facebook media can be re-minted. On other platforms the stored url is returned as-is when it still resolves, and `404` otherwise.
468
+ Resolve one attachment on a message to a media url that works right now. Instagram and Facebook sign DM media urls per request and expire them, so the `url` on a message is a snapshot: it works when you read the message and stops working later. This endpoint checks the stored url and, when it has gone stale, re-mints the message's media from Meta and persists it before answering. The message id never expires, so this URL is the one to store. It is returned ready-made on each attachment as `refreshUrl` when you read a message over REST. **Webhook payloads do not carry `refreshUrl`**, so a webhook-driven integration builds this URL itself. Every piece is in the event: `message.conversationId`, `message.platformMessageId`, the attachment's zero-based position, and `account.accountId`. Note that **`accountId` is a required query parameter**; omitting it returns `400` `missing_required_field`, which is the same requirement `GET /v1/whatsapp/media/{mediaId}` has. By default it responds `302` to the live media url, so it can be used directly as an `<img src>` on a browser session. API-key integrators should pass `?format=json` and read `url` off the body, since a browser cannot attach an Authorization header to an image request. Only Instagram and Facebook media can be re-minted. On other platforms the stored url is returned as-is when it still resolves, and `404` otherwise.
469
469
 
470
470
  ### Examples
471
471
 
@@ -482,7 +482,7 @@ api_instance = Zernio::MessagesApi.new
482
482
  conversation_id = 'conversation_id_example' # String | The conversation ID (Zernio id or platform conversation id)
483
483
  message_id = 'message_id_example' # String | The message id as returned by the list-messages endpoint (the platform message id)
484
484
  index = 56 # Integer | Zero-based position of the attachment in the message's attachments array
485
- account_id = 'account_id_example' # String | Social account ID
485
+ account_id = 'account_id_example' # String | Social account ID. Required: without it the request returns 400 missing_required_field.
486
486
  opts = {
487
487
  format: 'redirect' # String | `redirect` (default) answers 302 to the media; `json` returns the url in the body
488
488
  }
@@ -521,7 +521,7 @@ end
521
521
  | **conversation_id** | **String** | The conversation ID (Zernio id or platform conversation id) | |
522
522
  | **message_id** | **String** | The message id as returned by the list-messages endpoint (the platform message id) | |
523
523
  | **index** | **Integer** | Zero-based position of the attachment in the message&#39;s attachments array | |
524
- | **account_id** | **String** | Social account ID | |
524
+ | **account_id** | **String** | Social account ID. Required: without it the request returns 400 missing_required_field. | |
525
525
  | **format** | **String** | &#x60;redirect&#x60; (default) answers 302 to the media; &#x60;json&#x60; returns the url in the body | [optional][default to &#39;redirect&#39;] |
526
526
 
527
527
  ### Return type
@@ -4,8 +4,9 @@
4
4
 
5
5
  | Name | Type | Description | Notes |
6
6
  | ---- | ---- | ----------- | ----- |
7
- | **type** | **String** | Attachment type (image, video, file, sticker, audio) | |
8
- | **url** | **String** | Where to fetch the attachment. **The contract differs by platform.** - **WhatsApp**: points at &#x60;GET /v1/whatsapp/media/{mediaId}&#x60;, an authenticated Zernio endpoint. You MUST send &#x60;Authorization: Bearer &lt;your API key&gt;&#x60;; fetching it without that header returns &#x60;401&#x60;. Download and store the bytes when this webhook arrives: Meta drops inbound media after a limited retention window, after which the endpoint answers &#x60;400&#x60; permanently and the media is unrecoverable. - **Instagram / Facebook / Telegram**: a direct platform CDN link that needs no authentication and expires on the platform&#39;s own schedule. | |
7
+ | **type** | **String** | Attachment type (image, video, file, sticker, audio, share) | |
8
+ | **original_type** | **String** | Instagram and Facebook only, and present only when it differs from &#x60;type&#x60;. Meta&#39;s own attachment type before Zernio normalized it: &#x60;ig_reel&#x60; and &#x60;reel&#x60; become &#x60;video&#x60;, while &#x60;ig_post&#x60;, &#x60;post&#x60;, &#x60;ig_story&#x60; and &#x60;story_mention&#x60; all become &#x60;share&#x60;. Read it before rendering, because &#x60;type: \&quot;share\&quot;&#x60; alone is ambiguous. In particular a story mention arrives as &#x60;type: \&quot;share\&quot;&#x60; with &#x60;originalType: \&quot;story_mention\&quot;&#x60;; treating an unrecognized type as a generic document shows your agent \&quot;document received\&quot; for what is usually a lead. | [optional] |
9
+ | **url** | **String** | Where to fetch the attachment. **The contract differs by platform.** - **WhatsApp**: points at &#x60;GET /v1/whatsapp/media/{mediaId}&#x60;, an authenticated Zernio endpoint. You MUST send &#x60;Authorization: Bearer &lt;your API key&gt;&#x60;; fetching it without that header returns &#x60;401&#x60;. Download and store the bytes when this webhook arrives: Meta drops inbound media after a limited retention window, after which the endpoint answers &#x60;400&#x60; permanently and the media is unrecoverable. - **Instagram / Facebook / Telegram**: a direct platform CDN link that needs no authentication and expires on the platform&#39;s own schedule. **Webhook attachments carry no &#x60;refreshUrl&#x60;.** That field is stamped only when you read a message back over REST (&#x60;GET /v1/inbox/conversations/{conversationId}/messages&#x60;). On Instagram and Facebook the url above is a signed Meta CDN link that expires, so do not persist it: store the message id and resolve the media through &#x60;GET /v1/inbox/conversations/{conversationId}/messages/{messageId}/attachments/{index}?accountId&#x3D;{accountId}&#x60;, which re-mints it on demand. Every value that URL needs is already in this payload: &#x60;message.conversationId&#x60;, &#x60;message.platformMessageId&#x60;, &#x60;account.accountId&#x60;, and the attachment&#39;s zero-based position in this array. | |
9
10
  | **payload** | **Object** | Additional attachment metadata | [optional] |
10
11
 
11
12
  ## Example
@@ -15,6 +16,7 @@ require 'zernio-sdk'
15
16
 
16
17
  instance = Zernio::WebhookPayloadMessageMessageAttachmentsInner.new(
17
18
  type: null,
19
+ original_type: null,
18
20
  url: null,
19
21
  payload: null
20
22
  )
@@ -4,8 +4,9 @@
4
4
 
5
5
  | Name | Type | Description | Notes |
6
6
  | ---- | ---- | ----------- | ----- |
7
- | **type** | **String** | Attachment type (image, video, file, sticker, audio) | |
8
- | **url** | **String** | Where to fetch the attachment. For outgoing messages this is the media URL as sent, so for WhatsApp it is the URL you supplied when publishing (WhatsApp sends media by link), not a Zernio endpoint, and it needs no Zernio credentials. Contrast the inbound direction: &#x60;message.received&#x60; attachment URLs on WhatsApp point at the authenticated &#x60;GET /v1/whatsapp/media/{mediaId}&#x60;. | |
7
+ | **type** | **String** | Attachment type (image, video, file, sticker, audio, share) | |
8
+ | **original_type** | **String** | Instagram and Facebook only, and present only when it differs from &#x60;type&#x60;. Meta&#39;s own attachment type before Zernio normalized it. See the same field on message.received for the full mapping. | [optional] |
9
+ | **url** | **String** | Where to fetch the attachment. For outgoing messages this is the media URL as sent, so for WhatsApp it is the URL you supplied when publishing (WhatsApp sends media by link), not a Zernio endpoint, and it needs no Zernio credentials. Contrast the inbound direction: &#x60;message.received&#x60; attachment URLs on WhatsApp point at the authenticated &#x60;GET /v1/whatsapp/media/{mediaId}&#x60;. As on &#x60;message.received&#x60;, webhook attachments carry no &#x60;refreshUrl&#x60;: that field is stamped only on the REST read. Resolve Instagram and Facebook media through &#x60;GET /v1/inbox/conversations/{conversationId}/messages/{messageId}/attachments/{index}?accountId&#x3D;{accountId}&#x60;. | |
9
10
  | **payload** | **Object** | Additional attachment metadata | [optional] |
10
11
 
11
12
  ## Example
@@ -15,6 +16,7 @@ require 'zernio-sdk'
15
16
 
16
17
  instance = Zernio::WebhookPayloadMessageSentMessageAttachmentsInner.new(
17
18
  type: null,
19
+ original_type: null,
18
20
  url: null,
19
21
  payload: null
20
22
  )
@@ -4,11 +4,11 @@
4
4
 
5
5
  | Name | Type | Description | Notes |
6
6
  | ---- | ---- | ----------- | ----- |
7
- | **id** | **String** | | |
7
+ | **id** | **String** | The Zernio account id of the connected account that sent the message, not a contact id. | |
8
8
  | **contact_id** | **String** | Always omitted on this event: the sender is the business, not a contact. Use conversation.contactId to join back to the CRM Contact. | [optional] |
9
- | **name** | **String** | | [optional] |
10
- | **username** | **String** | | [optional] |
11
- | **picture** | **String** | | [optional] |
9
+ | **name** | **String** | Display name of your connected account. | [optional] |
10
+ | **username** | **String** | Username of your connected account. | [optional] |
11
+ | **picture** | **String** | Profile picture of your connected account. | [optional] |
12
12
 
13
13
  ## Example
14
14
 
@@ -297,12 +297,12 @@ module Zernio
297
297
  end
298
298
 
299
299
  # Connect ads for a platform
300
- # Unified ads connection endpoint. Creates a dedicated ads SocialAccount for the specified platform. Same-token platforms (facebook, instagram, linkedin, pinterest): Creates an ads SocialAccount (metaads, linkedinads, pinterestads) with a copied OAuth token from the parent posting account. If the ads account already exists, returns alreadyConnected: true. No extra OAuth needed. Separate-token platforms (tiktok, twitter): Starts the platform-specific marketing API OAuth flow and creates an ads SocialAccount (tiktokads, xads) with its own token. If the ads account already exists, returns alreadyConnected: true. - tiktok: accountId is OPTIONAL. With accountId, the new tiktokads account links to that posting account (parentAccountId set) — Spark Ads + standalone ads using the posting TT_USER identity become available. Without accountId, ads-only mode kicks in: the new tiktokads account has parentAccountId=null and standalone ads use a synthetic CUSTOMIZED_USER (\"Brand Identity\"); Spark Ads are unavailable because TikTok requires a posting account for them. The Brand Identity is configured separately via PATCH /v1/connect/tiktok-ads (or inline on POST /v1/ads/create via the brandIdentity field). - twitter (X Ads): accountId is REQUIRED. There's no ads-only mode — tweets need to be authored by a real X user. Standalone platforms (googleads): Starts the Google Ads OAuth flow and creates a standalone ads SocialAccount (googleads) with no parent. If the account already exists, returns alreadyConnected: true. Ads accounts appear as regular SocialAccount documents with ads platform values (e.g., metaads, tiktokads) in GET /v1/accounts.
301
- # @param platform [String] Platform to connect ads for. Only platforms with ads support are accepted.
300
+ # Unified ads connection endpoint. Creates a dedicated ads SocialAccount for the specified platform. Same-token platforms (facebook, instagram, linkedin, pinterest): the ads SocialAccount (metaads, linkedinads, pinterestads) reuses the OAuth token of the parent posting account, but only when an active parent exists and, for facebook and instagram, its stored token carries ads_management and ads_read (linkedin and pinterest need no extra scope). In that case no extra OAuth happens and the response is alreadyConnected: true. When no such parent exists, or the scopes are missing, the endpoint returns an authUrl and a full OAuth round trip is required. When a parent exists but carries no token usable for ad accounts, the call fails with 400 RECONNECT_REQUIRED. Independently of the branch, the call can return 403 ADS_ADDON_REQUIRED without the ads add-on and 402 PAYMENT_REQUIRED when the billing gate is closed. Meta Ads prerequisite: connecting Meta Ads (via facebook or instagram) requires a Facebook Page. Not because the ad account is read through a Page, but because both parent posting accounts are: the facebook flow only offers Pages you manage, and the instagram flow with loginMethod=facebook_login only offers Instagram accounts linked to one of those Pages. Without a Page there is no parent account to inherit a token from. A user who manages no Facebook Page cannot complete this connection, and the facebook flow ends with error=no_facebook_pages. Separate-token platforms (tiktok, twitter): Starts the platform-specific marketing API OAuth flow and creates an ads SocialAccount (tiktokads, xads) with its own token. If the ads account already exists, returns alreadyConnected: true. - tiktok: accountId is OPTIONAL. With accountId, the new tiktokads account links to that posting account (parentAccountId set) — Spark Ads + standalone ads using the posting TT_USER identity become available. Without accountId, ads-only mode kicks in: the new tiktokads account has parentAccountId=null and standalone ads use a synthetic CUSTOMIZED_USER (\"Brand Identity\"); Spark Ads are unavailable because TikTok requires a posting account for them. The Brand Identity is configured separately via PATCH /v1/connect/tiktok-ads (or inline on POST /v1/ads/create via the brandIdentity field). - twitter (X Ads): accountId is REQUIRED. There's no ads-only mode — tweets need to be authored by a real X user. Standalone platforms (googleads): Starts the Google Ads OAuth flow and creates a standalone ads SocialAccount (googleads) with no parent. If the account already exists, returns alreadyConnected: true. Ads accounts appear as regular SocialAccount documents with ads platform values (e.g., metaads, tiktokads) in GET /v1/accounts.
301
+ # @param platform [String] Platform to connect ads for. Only platforms with ads support are accepted. &#x60;instagram&#x60; requires an Instagram account connected with loginMethod&#x3D;facebook_login whose token carries ads_management and ads_read. With an account connected through the default instagram_login flow no ads account can be created; do not use this value for those accounts.
302
302
  # @param profile_id [String] Your Zernio profile ID
303
303
  # @param [Hash] opts the optional parameters
304
304
  # @option opts [String] :account_id Existing SocialAccount ID. Required for &#x60;twitter&#x60; (X Ads). Optional for &#x60;tiktok&#x60; — omit to enter ads-only mode (no TikTok posting account linked; ad creation uses a Brand Identity instead of a TT_USER). Ignored for same-token (&#x60;facebook&#x60;, &#x60;instagram&#x60;, &#x60;linkedin&#x60;, &#x60;pinterest&#x60;) and standalone (&#x60;googleads&#x60;) platforms.
305
- # @option opts [String] :redirect_url Custom URL the browser is sent to once the OAuth flow finishes. Honored on every ads platform, including the separate-token (&#x60;tiktok&#x60;, &#x60;twitter&#x60;) and standalone (&#x60;googleads&#x60;) flows. Accepts an http(s) URL, a custom app scheme for mobile deeplinks (e.g. myapp://callback), or a relative path. On success &#x60;tiktok&#x60;, &#x60;twitter&#x60; and &#x60;googleads&#x60; land on the URL unchanged, while the same-token platforms (&#x60;facebook&#x60;, &#x60;instagram&#x60;, &#x60;linkedin&#x60;, &#x60;pinterest&#x60;) append &#x60;connected&#x60;, &#x60;profileId&#x60;, &#x60;accountId&#x60;, &#x60;username&#x60; and, on API-key calls, &#x60;connect_token&#x60;. On failure every platform appends error details, starting with &#x60;error&#x60; and &#x60;platform&#x60;. When omitted, the browser lands on the Zernio dashboard.
305
+ # @option opts [String] :redirect_url Custom URL the browser is sent to once the OAuth flow finishes. Honored on every ads platform, including the separate-token (&#x60;tiktok&#x60;, &#x60;twitter&#x60;) and standalone (&#x60;googleads&#x60;) flows. Accepts an http(s) URL, a custom app scheme for mobile deeplinks (e.g. myapp://callback), or a relative path. On success &#x60;tiktok&#x60;, &#x60;twitter&#x60; and &#x60;googleads&#x60; land on the URL unchanged, while the same-token platforms (&#x60;facebook&#x60;, &#x60;instagram&#x60;, &#x60;linkedin&#x60;, &#x60;pinterest&#x60;) append &#x60;connected&#x60;, &#x60;profileId&#x60;, &#x60;accountId&#x60;, &#x60;username&#x60; and, on API-key calls, &#x60;connect_token&#x60;. On failure the same error contract applies as on GET /v1/connect/{platform}: &#x60;error&#x60; and &#x60;platform&#x60; are always appended, other params are optional, and the value list there is not exhaustive. Note that on the tiktok, twitter and googleads flows &#x60;platform&#x60; carries the ads platform id (&#x60;tiktokads&#x60;, &#x60;xads&#x60;, &#x60;googleads&#x60;), not the value used in the request path. When omitted, the browser lands on the Zernio dashboard.
306
306
  # @option opts [Boolean] :headless Enable headless mode (same-token platforms only) (default to false)
307
307
  # @option opts [Boolean] :force Force a fresh OAuth even when an account already exists. Normally the endpoint returns &#x60;alreadyConnected: true&#x60; whenever a connected account is found, keying off its active state rather than token liveness. Set &#x60;force&#x3D;true&#x60; to bypass that and always receivean &#x60;authUrl&#x60;. Completing the returned OAuth refreshes the stored token on the existing posting and ads accounts in place. (default to false)
308
308
  # @option opts [String] :ad_account_id Scope ad sync to a single platform ad account. Without this param, sync covers every ad account the connected token can see. Supported on &#x60;facebook&#x60;/&#x60;instagram&#x60; (Meta, &#x60;act_&lt;digits&gt;&#x60;), &#x60;linkedin&#x60; (bare numeric sponsored-account id), &#x60;googleads&#x60; (bare customer id digits) and &#x60;twitter&#x60; (X Ads, base36 account id). &#x60;tiktok&#x60; scopes advertisers at OAuth and &#x60;pinterest&#x60; has no ads discovery, so both ignore it. Meta ids are additionally validated against the connected token; unreachable IDs return 400. Setting a scope also removes already synced ads from de-scoped ad accounts. For multiple accounts use &#x60;adAccountIds&#x60; instead.
@@ -314,12 +314,12 @@ module Zernio
314
314
  end
315
315
 
316
316
  # Connect ads for a platform
317
- # Unified ads connection endpoint. Creates a dedicated ads SocialAccount for the specified platform. Same-token platforms (facebook, instagram, linkedin, pinterest): Creates an ads SocialAccount (metaads, linkedinads, pinterestads) with a copied OAuth token from the parent posting account. If the ads account already exists, returns alreadyConnected: true. No extra OAuth needed. Separate-token platforms (tiktok, twitter): Starts the platform-specific marketing API OAuth flow and creates an ads SocialAccount (tiktokads, xads) with its own token. If the ads account already exists, returns alreadyConnected: true. - tiktok: accountId is OPTIONAL. With accountId, the new tiktokads account links to that posting account (parentAccountId set) — Spark Ads + standalone ads using the posting TT_USER identity become available. Without accountId, ads-only mode kicks in: the new tiktokads account has parentAccountId&#x3D;null and standalone ads use a synthetic CUSTOMIZED_USER (\&quot;Brand Identity\&quot;); Spark Ads are unavailable because TikTok requires a posting account for them. The Brand Identity is configured separately via PATCH /v1/connect/tiktok-ads (or inline on POST /v1/ads/create via the brandIdentity field). - twitter (X Ads): accountId is REQUIRED. There&#39;s no ads-only mode — tweets need to be authored by a real X user. Standalone platforms (googleads): Starts the Google Ads OAuth flow and creates a standalone ads SocialAccount (googleads) with no parent. If the account already exists, returns alreadyConnected: true. Ads accounts appear as regular SocialAccount documents with ads platform values (e.g., metaads, tiktokads) in GET /v1/accounts.
318
- # @param platform [String] Platform to connect ads for. Only platforms with ads support are accepted.
317
+ # Unified ads connection endpoint. Creates a dedicated ads SocialAccount for the specified platform. Same-token platforms (facebook, instagram, linkedin, pinterest): the ads SocialAccount (metaads, linkedinads, pinterestads) reuses the OAuth token of the parent posting account, but only when an active parent exists and, for facebook and instagram, its stored token carries ads_management and ads_read (linkedin and pinterest need no extra scope). In that case no extra OAuth happens and the response is alreadyConnected: true. When no such parent exists, or the scopes are missing, the endpoint returns an authUrl and a full OAuth round trip is required. When a parent exists but carries no token usable for ad accounts, the call fails with 400 RECONNECT_REQUIRED. Independently of the branch, the call can return 403 ADS_ADDON_REQUIRED without the ads add-on and 402 PAYMENT_REQUIRED when the billing gate is closed. Meta Ads prerequisite: connecting Meta Ads (via facebook or instagram) requires a Facebook Page. Not because the ad account is read through a Page, but because both parent posting accounts are: the facebook flow only offers Pages you manage, and the instagram flow with loginMethod&#x3D;facebook_login only offers Instagram accounts linked to one of those Pages. Without a Page there is no parent account to inherit a token from. A user who manages no Facebook Page cannot complete this connection, and the facebook flow ends with error&#x3D;no_facebook_pages. Separate-token platforms (tiktok, twitter): Starts the platform-specific marketing API OAuth flow and creates an ads SocialAccount (tiktokads, xads) with its own token. If the ads account already exists, returns alreadyConnected: true. - tiktok: accountId is OPTIONAL. With accountId, the new tiktokads account links to that posting account (parentAccountId set) — Spark Ads + standalone ads using the posting TT_USER identity become available. Without accountId, ads-only mode kicks in: the new tiktokads account has parentAccountId&#x3D;null and standalone ads use a synthetic CUSTOMIZED_USER (\&quot;Brand Identity\&quot;); Spark Ads are unavailable because TikTok requires a posting account for them. The Brand Identity is configured separately via PATCH /v1/connect/tiktok-ads (or inline on POST /v1/ads/create via the brandIdentity field). - twitter (X Ads): accountId is REQUIRED. There&#39;s no ads-only mode — tweets need to be authored by a real X user. Standalone platforms (googleads): Starts the Google Ads OAuth flow and creates a standalone ads SocialAccount (googleads) with no parent. If the account already exists, returns alreadyConnected: true. Ads accounts appear as regular SocialAccount documents with ads platform values (e.g., metaads, tiktokads) in GET /v1/accounts.
318
+ # @param platform [String] Platform to connect ads for. Only platforms with ads support are accepted. &#x60;instagram&#x60; requires an Instagram account connected with loginMethod&#x3D;facebook_login whose token carries ads_management and ads_read. With an account connected through the default instagram_login flow no ads account can be created; do not use this value for those accounts.
319
319
  # @param profile_id [String] Your Zernio profile ID
320
320
  # @param [Hash] opts the optional parameters
321
321
  # @option opts [String] :account_id Existing SocialAccount ID. Required for &#x60;twitter&#x60; (X Ads). Optional for &#x60;tiktok&#x60; — omit to enter ads-only mode (no TikTok posting account linked; ad creation uses a Brand Identity instead of a TT_USER). Ignored for same-token (&#x60;facebook&#x60;, &#x60;instagram&#x60;, &#x60;linkedin&#x60;, &#x60;pinterest&#x60;) and standalone (&#x60;googleads&#x60;) platforms.
322
- # @option opts [String] :redirect_url Custom URL the browser is sent to once the OAuth flow finishes. Honored on every ads platform, including the separate-token (&#x60;tiktok&#x60;, &#x60;twitter&#x60;) and standalone (&#x60;googleads&#x60;) flows. Accepts an http(s) URL, a custom app scheme for mobile deeplinks (e.g. myapp://callback), or a relative path. On success &#x60;tiktok&#x60;, &#x60;twitter&#x60; and &#x60;googleads&#x60; land on the URL unchanged, while the same-token platforms (&#x60;facebook&#x60;, &#x60;instagram&#x60;, &#x60;linkedin&#x60;, &#x60;pinterest&#x60;) append &#x60;connected&#x60;, &#x60;profileId&#x60;, &#x60;accountId&#x60;, &#x60;username&#x60; and, on API-key calls, &#x60;connect_token&#x60;. On failure every platform appends error details, starting with &#x60;error&#x60; and &#x60;platform&#x60;. When omitted, the browser lands on the Zernio dashboard.
322
+ # @option opts [String] :redirect_url Custom URL the browser is sent to once the OAuth flow finishes. Honored on every ads platform, including the separate-token (&#x60;tiktok&#x60;, &#x60;twitter&#x60;) and standalone (&#x60;googleads&#x60;) flows. Accepts an http(s) URL, a custom app scheme for mobile deeplinks (e.g. myapp://callback), or a relative path. On success &#x60;tiktok&#x60;, &#x60;twitter&#x60; and &#x60;googleads&#x60; land on the URL unchanged, while the same-token platforms (&#x60;facebook&#x60;, &#x60;instagram&#x60;, &#x60;linkedin&#x60;, &#x60;pinterest&#x60;) append &#x60;connected&#x60;, &#x60;profileId&#x60;, &#x60;accountId&#x60;, &#x60;username&#x60; and, on API-key calls, &#x60;connect_token&#x60;. On failure the same error contract applies as on GET /v1/connect/{platform}: &#x60;error&#x60; and &#x60;platform&#x60; are always appended, other params are optional, and the value list there is not exhaustive. Note that on the tiktok, twitter and googleads flows &#x60;platform&#x60; carries the ads platform id (&#x60;tiktokads&#x60;, &#x60;xads&#x60;, &#x60;googleads&#x60;), not the value used in the request path. When omitted, the browser lands on the Zernio dashboard.
323
323
  # @option opts [Boolean] :headless Enable headless mode (same-token platforms only) (default to false)
324
324
  # @option opts [Boolean] :force Force a fresh OAuth even when an account already exists. Normally the endpoint returns &#x60;alreadyConnected: true&#x60; whenever a connected account is found, keying off its active state rather than token liveness. Set &#x60;force&#x3D;true&#x60; to bypass that and always receivean &#x60;authUrl&#x60;. Completing the returned OAuth refreshes the stored token on the existing posting and ads accounts in place. (default to false)
325
325
  # @option opts [String] :ad_account_id Scope ad sync to a single platform ad account. Without this param, sync covers every ad account the connected token can see. Supported on &#x60;facebook&#x60;/&#x60;instagram&#x60; (Meta, &#x60;act_&lt;digits&gt;&#x60;), &#x60;linkedin&#x60; (bare numeric sponsored-account id), &#x60;googleads&#x60; (bare customer id digits) and &#x60;twitter&#x60; (X Ads, base36 account id). &#x60;tiktok&#x60; scopes advertisers at OAuth and &#x60;pinterest&#x60; has no ads discovery, so both ignore it. Meta ids are additionally validated against the connected token; unreachable IDs return 400. Setting a scope also removes already synced ads from de-scoped ad accounts. For multiple accounts use &#x60;adAccountIds&#x60; instead.
@@ -944,7 +944,7 @@ module Zernio
944
944
  # @param platform [String] Social media platform to connect
945
945
  # @param profile_id [String] Your Zernio profile ID (get from /v1/profiles). For WhatsApp, a Zernio-provisioned number can only be connected on the profile it was provisioned to; connecting from any other profile is rejected with a 409.
946
946
  # @param [Hash] opts the optional parameters
947
- # @option opts [String] :redirect_url Your custom redirect URL after connection completes. Accepts an http(s) URL, a custom app scheme for mobile deeplinks (e.g. myapp://callback), or a relative path. Result params are appended with the URL API, so an existing query string is preserved. Standard mode appends connected&#x3D;{platform}&amp;profileId&#x3D;X&amp;accountId&#x3D;Y&amp;username&#x3D;Z. Headless mode appends OAuth data params for platforms requiring selection (e.g. LinkedIn orgs, Facebook pages). If no selection is needed, the account is created directly and the redirect includes accountId.
947
+ # @option opts [String] :redirect_url Your custom redirect URL after connection completes. Accepts an http(s) URL, a custom app scheme for mobile deeplinks (e.g. myapp://callback), or a relative path. Result params are appended with the URL API, so an existing query string is preserved. Standard mode appends connected&#x3D;{platform}&amp;profileId&#x3D;X&amp;accountId&#x3D;Y&amp;username&#x3D;Z. Headless mode appends OAuth data params for platforms requiring selection (e.g. LinkedIn orgs, Facebook pages). If no selection is needed, the account is created directly and the redirect includes accountId. On failure, the browser is sent to the same redirect_url with &#x60;error&#x60; and &#x60;platform&#x60; appended. &#x60;error&#x60; and &#x60;platform&#x60; are always present. &#x60;error_message&#x60;, &#x60;is_user_fixable&#x60;, &#x60;reason&#x60; and &#x60;dashboard_url&#x60; are conditional and must be treated as optional. This list is NOT exhaustive and new values may be added at any time. Treat an unrecognized value as a generic failure rather than matching it exhaustively. Existing values are not renamed or removed without notice. OAuth and callback: oauth_denied, invalid_callback, invalid_state, unsupported_platform, connection_failed, internal_error, token_exchange_failed, byok_config_error, personal_account_not_supported, missing_google_permissions, platform_requires_destination, reconnect_account_mismatch, invalid_request Access and limits: profile_not_found, invalid_profile_id, access_denied, account_limit_exceeded, profile_limit_exceeded, payment_required Destination selection: no_facebook_pages, facebook_pages_error, no_google_locations, google_locations_error, google_permission_denied, no_snapchat_public_profiles, snapchat_profiles_error, discord_no_guild, slack_no_team WhatsApp: whatsapp_error, one_whatsapp_per_profile, whatsapp_number_already_connected, whatsapp_number_pinned_to_profile, connection_cancelled Google Ads (platform&#x3D;googleads): google_ads_auth_failed, google_ads_invalid_state, google_ads_config_error, google_ads_token_failed, google_ads_quota_exhausted, google_ads_callback_error TikTok Ads (platform&#x3D;tiktokads): tiktok_ads_auth_failed, tiktok_ads_invalid_state, tiktok_ads_access_denied, tiktok_ads_config_error, tiktok_ads_token_failed, tiktok_ads_account_not_found, tiktok_ads_callback_error X Ads (platform&#x3D;xads): x_ads_denied, x_ads_auth_failed, x_ads_config_error, x_ads_account_not_found, x_ads_state_error, x_ads_token_failed, x_ads_token_missing, x_ads_callback_error Shopify (platform&#x3D;shopify): shopify_auth_failed, shopify_config_error, shopify_invalid_state, shopify_invalid_hmac, shopify_invalid_shop, shopify_missing_scopes, shopify_callback_error 1. On this endpoint every upstream OAuth error is collapsed into &#x60;oauth_denied&#x60;. The provider&#39;s own value (for example Meta&#39;s &#x60;access_denied&#x60;) is not forwarded. The dedicated ads flows below are different: they use their own denial slugs and &#x60;google_ads_auth_failed&#x60; and &#x60;tiktok_ads_auth_failed&#x60; may carry the provider&#39;s raw error string in &#x60;error_message&#x60;. 2. On the tiktok and twitter ads flows &#x60;platform&#x60; carries the ads platform id (&#x60;tiktokads&#x60;, &#x60;xads&#x60;), not the value used in the request path. The googleads and shopify flows report &#x60;googleads&#x60; and &#x60;shopify&#x60;.
948
948
  # @option opts [Boolean] :headless When true, the user is redirected to your redirect_url with raw OAuth data (code, state) instead of Zernio&#39;s default account selection UI. Use this to build a custom connect experience. (default to false)
949
949
  # @option opts [String] :login_method Instagram only. Which of the two Instagram connection methods to use. Ignored for every other platform. &#x60;instagram_login&#x60; (the default, and what you get if you omit this): the Instagram Login dialog. The user authorizes their Instagram professional account directly, no Facebook Page required. &#x60;facebook_login&#x60;: the Facebook Login dialog, i.e. \&quot;Instagram API with Facebook Login\&quot;. The user authorizes a Facebook Page that has a linked Instagram professional account, and every API call for that account then runs through the Page. Use this when the customer manages Instagram through a Page and expects the Facebook consent screen. Because the user has to pick which Page to connect, the callback continues at the account-selection step, &#x60;/v1/connect/instagram/select-account&#x60;. &#x60;facebook_login&#x60; supports &#x60;headless&#x3D;true&#x60; like the other selection platforms: the callback redirects to your &#x60;redirect_url&#x60; with &#x60;profileId&#x60;, &#x60;tempToken&#x60;, &#x60;platform&#x3D;instagram&#x60;, &#x60;step&#x3D;select_account&#x60; and &#x60;connect_token&#x60;, which you pass into the select-account endpoints to finish. The default &#x60;instagram_login&#x60; has no selection step, so it connects the account directly. (default to 'instagram_login')
950
950
  # @option opts [String] :onboarding WhatsApp only. Ignored for every other platform. Controls which screen Meta&#39;s Embedded Signup popup shows. If omitted, the connection defaults to coexistence (same as &#x60;business_app&#x60; below), preserving existing behavior for numbers already on the WhatsApp Business app. &#x60;api&#x60;: standard Embedded Signup, showing Meta&#39;s WABA/number picker. Use this to connect a phone number already on Cloud API elsewhere. &#x60;business_app&#x60;: coexistence, i.e. &#39;Connect existing WhatsApp Business app&#39; (a number shared between Cloud API and the consumer WhatsApp Business app).
@@ -959,7 +959,7 @@ module Zernio
959
959
  # @param platform [String] Social media platform to connect
960
960
  # @param profile_id [String] Your Zernio profile ID (get from /v1/profiles). For WhatsApp, a Zernio-provisioned number can only be connected on the profile it was provisioned to; connecting from any other profile is rejected with a 409.
961
961
  # @param [Hash] opts the optional parameters
962
- # @option opts [String] :redirect_url Your custom redirect URL after connection completes. Accepts an http(s) URL, a custom app scheme for mobile deeplinks (e.g. myapp://callback), or a relative path. Result params are appended with the URL API, so an existing query string is preserved. Standard mode appends connected&#x3D;{platform}&amp;profileId&#x3D;X&amp;accountId&#x3D;Y&amp;username&#x3D;Z. Headless mode appends OAuth data params for platforms requiring selection (e.g. LinkedIn orgs, Facebook pages). If no selection is needed, the account is created directly and the redirect includes accountId.
962
+ # @option opts [String] :redirect_url Your custom redirect URL after connection completes. Accepts an http(s) URL, a custom app scheme for mobile deeplinks (e.g. myapp://callback), or a relative path. Result params are appended with the URL API, so an existing query string is preserved. Standard mode appends connected&#x3D;{platform}&amp;profileId&#x3D;X&amp;accountId&#x3D;Y&amp;username&#x3D;Z. Headless mode appends OAuth data params for platforms requiring selection (e.g. LinkedIn orgs, Facebook pages). If no selection is needed, the account is created directly and the redirect includes accountId. On failure, the browser is sent to the same redirect_url with &#x60;error&#x60; and &#x60;platform&#x60; appended. &#x60;error&#x60; and &#x60;platform&#x60; are always present. &#x60;error_message&#x60;, &#x60;is_user_fixable&#x60;, &#x60;reason&#x60; and &#x60;dashboard_url&#x60; are conditional and must be treated as optional. This list is NOT exhaustive and new values may be added at any time. Treat an unrecognized value as a generic failure rather than matching it exhaustively. Existing values are not renamed or removed without notice. OAuth and callback: oauth_denied, invalid_callback, invalid_state, unsupported_platform, connection_failed, internal_error, token_exchange_failed, byok_config_error, personal_account_not_supported, missing_google_permissions, platform_requires_destination, reconnect_account_mismatch, invalid_request Access and limits: profile_not_found, invalid_profile_id, access_denied, account_limit_exceeded, profile_limit_exceeded, payment_required Destination selection: no_facebook_pages, facebook_pages_error, no_google_locations, google_locations_error, google_permission_denied, no_snapchat_public_profiles, snapchat_profiles_error, discord_no_guild, slack_no_team WhatsApp: whatsapp_error, one_whatsapp_per_profile, whatsapp_number_already_connected, whatsapp_number_pinned_to_profile, connection_cancelled Google Ads (platform&#x3D;googleads): google_ads_auth_failed, google_ads_invalid_state, google_ads_config_error, google_ads_token_failed, google_ads_quota_exhausted, google_ads_callback_error TikTok Ads (platform&#x3D;tiktokads): tiktok_ads_auth_failed, tiktok_ads_invalid_state, tiktok_ads_access_denied, tiktok_ads_config_error, tiktok_ads_token_failed, tiktok_ads_account_not_found, tiktok_ads_callback_error X Ads (platform&#x3D;xads): x_ads_denied, x_ads_auth_failed, x_ads_config_error, x_ads_account_not_found, x_ads_state_error, x_ads_token_failed, x_ads_token_missing, x_ads_callback_error Shopify (platform&#x3D;shopify): shopify_auth_failed, shopify_config_error, shopify_invalid_state, shopify_invalid_hmac, shopify_invalid_shop, shopify_missing_scopes, shopify_callback_error 1. On this endpoint every upstream OAuth error is collapsed into &#x60;oauth_denied&#x60;. The provider&#39;s own value (for example Meta&#39;s &#x60;access_denied&#x60;) is not forwarded. The dedicated ads flows below are different: they use their own denial slugs and &#x60;google_ads_auth_failed&#x60; and &#x60;tiktok_ads_auth_failed&#x60; may carry the provider&#39;s raw error string in &#x60;error_message&#x60;. 2. On the tiktok and twitter ads flows &#x60;platform&#x60; carries the ads platform id (&#x60;tiktokads&#x60;, &#x60;xads&#x60;), not the value used in the request path. The googleads and shopify flows report &#x60;googleads&#x60; and &#x60;shopify&#x60;.
963
963
  # @option opts [Boolean] :headless When true, the user is redirected to your redirect_url with raw OAuth data (code, state) instead of Zernio&#39;s default account selection UI. Use this to build a custom connect experience. (default to false)
964
964
  # @option opts [String] :login_method Instagram only. Which of the two Instagram connection methods to use. Ignored for every other platform. &#x60;instagram_login&#x60; (the default, and what you get if you omit this): the Instagram Login dialog. The user authorizes their Instagram professional account directly, no Facebook Page required. &#x60;facebook_login&#x60;: the Facebook Login dialog, i.e. \&quot;Instagram API with Facebook Login\&quot;. The user authorizes a Facebook Page that has a linked Instagram professional account, and every API call for that account then runs through the Page. Use this when the customer manages Instagram through a Page and expects the Facebook consent screen. Because the user has to pick which Page to connect, the callback continues at the account-selection step, &#x60;/v1/connect/instagram/select-account&#x60;. &#x60;facebook_login&#x60; supports &#x60;headless&#x3D;true&#x60; like the other selection platforms: the callback redirects to your &#x60;redirect_url&#x60; with &#x60;profileId&#x60;, &#x60;tempToken&#x60;, &#x60;platform&#x3D;instagram&#x60;, &#x60;step&#x3D;select_account&#x60; and &#x60;connect_token&#x60;, which you pass into the select-account endpoints to finish. The default &#x60;instagram_login&#x60; has no selection step, so it connects the account directly. (default to 'instagram_login')
965
965
  # @option opts [String] :onboarding WhatsApp only. Ignored for every other platform. Controls which screen Meta&#39;s Embedded Signup popup shows. If omitted, the connection defaults to coexistence (same as &#x60;business_app&#x60; below), preserving existing behavior for numbers already on the WhatsApp Business app. &#x60;api&#x60;: standard Embedded Signup, showing Meta&#39;s WABA/number picker. Use this to connect a phone number already on Cloud API elsewhere. &#x60;business_app&#x60;: coexistence, i.e. &#39;Connect existing WhatsApp Business app&#39; (a number shared between Cloud API and the consumer WhatsApp Business app).
@@ -485,11 +485,11 @@ module Zernio
485
485
  end
486
486
 
487
487
  # Resolve message attachment
488
- # Resolve one attachment on a message to a media url that works right now. Instagram and Facebook sign DM media urls per request and expire them, so the `url` on a message is a snapshot: it works when you read the message and stops working later. This endpoint checks the stored url and, when it has gone stale, re-mints the message's media from Meta and persists it before answering. The message id never expires, so this URL is the one to store — it is returned on each attachment as `refreshUrl`. By default it responds `302` to the live media url, so it can be used directly as an `<img src>` on a browser session. API-key integrators should pass `?format=json` and read `url` off the body, since a browser cannot attach an Authorization header to an image request. Only Instagram and Facebook media can be re-minted. On other platforms the stored url is returned as-is when it still resolves, and `404` otherwise.
488
+ # Resolve one attachment on a message to a media url that works right now. Instagram and Facebook sign DM media urls per request and expire them, so the `url` on a message is a snapshot: it works when you read the message and stops working later. This endpoint checks the stored url and, when it has gone stale, re-mints the message's media from Meta and persists it before answering. The message id never expires, so this URL is the one to store. It is returned ready-made on each attachment as `refreshUrl` when you read a message over REST. **Webhook payloads do not carry `refreshUrl`**, so a webhook-driven integration builds this URL itself. Every piece is in the event: `message.conversationId`, `message.platformMessageId`, the attachment's zero-based position, and `account.accountId`. Note that **`accountId` is a required query parameter**; omitting it returns `400` `missing_required_field`, which is the same requirement `GET /v1/whatsapp/media/{mediaId}` has. By default it responds `302` to the live media url, so it can be used directly as an `<img src>` on a browser session. API-key integrators should pass `?format=json` and read `url` off the body, since a browser cannot attach an Authorization header to an image request. Only Instagram and Facebook media can be re-minted. On other platforms the stored url is returned as-is when it still resolves, and `404` otherwise.
489
489
  # @param conversation_id [String] The conversation ID (Zernio id or platform conversation id)
490
490
  # @param message_id [String] The message id as returned by the list-messages endpoint (the platform message id)
491
491
  # @param index [Integer] Zero-based position of the attachment in the message&#39;s attachments array
492
- # @param account_id [String] Social account ID
492
+ # @param account_id [String] Social account ID. Required: without it the request returns 400 missing_required_field.
493
493
  # @param [Hash] opts the optional parameters
494
494
  # @option opts [String] :format &#x60;redirect&#x60; (default) answers 302 to the media; &#x60;json&#x60; returns the url in the body (default to 'redirect')
495
495
  # @return [GetMessageAttachment200Response]
@@ -499,11 +499,11 @@ module Zernio
499
499
  end
500
500
 
501
501
  # Resolve message attachment
502
- # Resolve one attachment on a message to a media url that works right now. Instagram and Facebook sign DM media urls per request and expire them, so the &#x60;url&#x60; on a message is a snapshot: it works when you read the message and stops working later. This endpoint checks the stored url and, when it has gone stale, re-mints the message&#39;s media from Meta and persists it before answering. The message id never expires, so this URL is the one to store — it is returned on each attachment as &#x60;refreshUrl&#x60;. By default it responds &#x60;302&#x60; to the live media url, so it can be used directly as an &#x60;&lt;img src&gt;&#x60; on a browser session. API-key integrators should pass &#x60;?format&#x3D;json&#x60; and read &#x60;url&#x60; off the body, since a browser cannot attach an Authorization header to an image request. Only Instagram and Facebook media can be re-minted. On other platforms the stored url is returned as-is when it still resolves, and &#x60;404&#x60; otherwise.
502
+ # Resolve one attachment on a message to a media url that works right now. Instagram and Facebook sign DM media urls per request and expire them, so the &#x60;url&#x60; on a message is a snapshot: it works when you read the message and stops working later. This endpoint checks the stored url and, when it has gone stale, re-mints the message&#39;s media from Meta and persists it before answering. The message id never expires, so this URL is the one to store. It is returned ready-made on each attachment as &#x60;refreshUrl&#x60; when you read a message over REST. **Webhook payloads do not carry &#x60;refreshUrl&#x60;**, so a webhook-driven integration builds this URL itself. Every piece is in the event: &#x60;message.conversationId&#x60;, &#x60;message.platformMessageId&#x60;, the attachment&#39;s zero-based position, and &#x60;account.accountId&#x60;. Note that **&#x60;accountId&#x60; is a required query parameter**; omitting it returns &#x60;400&#x60; &#x60;missing_required_field&#x60;, which is the same requirement &#x60;GET /v1/whatsapp/media/{mediaId}&#x60; has. By default it responds &#x60;302&#x60; to the live media url, so it can be used directly as an &#x60;&lt;img src&gt;&#x60; on a browser session. API-key integrators should pass &#x60;?format&#x3D;json&#x60; and read &#x60;url&#x60; off the body, since a browser cannot attach an Authorization header to an image request. Only Instagram and Facebook media can be re-minted. On other platforms the stored url is returned as-is when it still resolves, and &#x60;404&#x60; otherwise.
503
503
  # @param conversation_id [String] The conversation ID (Zernio id or platform conversation id)
504
504
  # @param message_id [String] The message id as returned by the list-messages endpoint (the platform message id)
505
505
  # @param index [Integer] Zero-based position of the attachment in the message&#39;s attachments array
506
- # @param account_id [String] Social account ID
506
+ # @param account_id [String] Social account ID. Required: without it the request returns 400 missing_required_field.
507
507
  # @param [Hash] opts the optional parameters
508
508
  # @option opts [String] :format &#x60;redirect&#x60; (default) answers 302 to the media; &#x60;json&#x60; returns the url in the body (default to 'redirect')
509
509
  # @return [Array<(GetMessageAttachment200Response, Integer, Hash)>] GetMessageAttachment200Response data, response status code and response headers
@@ -19,6 +19,9 @@ module Zernio
19
19
 
20
20
  attr_accessor :type
21
21
 
22
+ # Instagram and Facebook only, and present only when it differs from `type`. Meta's own type before normalization: `ig_reel` and `reel` become `video`, while `ig_post`, `post`, `ig_story` and `story_mention` become `share`. A story mention is `type: \"share\"` with `originalType: \"story_mention\"`; render on this field, since `share` alone is ambiguous.
23
+ attr_accessor :original_type
24
+
22
25
  # Direct media link. On Instagram and Facebook this is a signed Meta CDN url that EXPIRES: use it now, do not store it. Persist `refreshUrl` instead.
23
26
  attr_accessor :url
24
27
 
@@ -56,6 +59,7 @@ module Zernio
56
59
  {
57
60
  :'id' => :'id',
58
61
  :'type' => :'type',
62
+ :'original_type' => :'originalType',
59
63
  :'url' => :'url',
60
64
  :'refresh_url' => :'refreshUrl',
61
65
  :'filename' => :'filename',
@@ -78,6 +82,7 @@ module Zernio
78
82
  {
79
83
  :'id' => :'String',
80
84
  :'type' => :'String',
85
+ :'original_type' => :'String',
81
86
  :'url' => :'String',
82
87
  :'refresh_url' => :'String',
83
88
  :'filename' => :'String',
@@ -118,6 +123,10 @@ module Zernio
118
123
  self.type = attributes[:'type']
119
124
  end
120
125
 
126
+ if attributes.key?(:'original_type')
127
+ self.original_type = attributes[:'original_type']
128
+ end
129
+
121
130
  if attributes.key?(:'url')
122
131
  self.url = attributes[:'url']
123
132
  end
@@ -169,6 +178,7 @@ module Zernio
169
178
  self.class == o.class &&
170
179
  id == o.id &&
171
180
  type == o.type &&
181
+ original_type == o.original_type &&
172
182
  url == o.url &&
173
183
  refresh_url == o.refresh_url &&
174
184
  filename == o.filename &&
@@ -184,7 +194,7 @@ module Zernio
184
194
  # Calculates hash code according to all attributes.
185
195
  # @return [Integer] Hash code
186
196
  def hash
187
- [id, type, url, refresh_url, filename, preview_url].hash
197
+ [id, type, original_type, url, refresh_url, filename, preview_url].hash
188
198
  end
189
199
 
190
200
  # Builds the object from hash
@@ -15,10 +15,13 @@ require 'time'
15
15
 
16
16
  module Zernio
17
17
  class WebhookPayloadMessageMessageAttachmentsInner < ApiModelBase
18
- # Attachment type (image, video, file, sticker, audio)
18
+ # Attachment type (image, video, file, sticker, audio, share)
19
19
  attr_accessor :type
20
20
 
21
- # Where to fetch the attachment. **The contract differs by platform.** - **WhatsApp**: points at `GET /v1/whatsapp/media/{mediaId}`, an authenticated Zernio endpoint. You MUST send `Authorization: Bearer <your API key>`; fetching it without that header returns `401`. Download and store the bytes when this webhook arrives: Meta drops inbound media after a limited retention window, after which the endpoint answers `400` permanently and the media is unrecoverable. - **Instagram / Facebook / Telegram**: a direct platform CDN link that needs no authentication and expires on the platform's own schedule.
21
+ # Instagram and Facebook only, and present only when it differs from `type`. Meta's own attachment type before Zernio normalized it: `ig_reel` and `reel` become `video`, while `ig_post`, `post`, `ig_story` and `story_mention` all become `share`. Read it before rendering, because `type: \"share\"` alone is ambiguous. In particular a story mention arrives as `type: \"share\"` with `originalType: \"story_mention\"`; treating an unrecognized type as a generic document shows your agent \"document received\" for what is usually a lead.
22
+ attr_accessor :original_type
23
+
24
+ # Where to fetch the attachment. **The contract differs by platform.** - **WhatsApp**: points at `GET /v1/whatsapp/media/{mediaId}`, an authenticated Zernio endpoint. You MUST send `Authorization: Bearer <your API key>`; fetching it without that header returns `401`. Download and store the bytes when this webhook arrives: Meta drops inbound media after a limited retention window, after which the endpoint answers `400` permanently and the media is unrecoverable. - **Instagram / Facebook / Telegram**: a direct platform CDN link that needs no authentication and expires on the platform's own schedule. **Webhook attachments carry no `refreshUrl`.** That field is stamped only when you read a message back over REST (`GET /v1/inbox/conversations/{conversationId}/messages`). On Instagram and Facebook the url above is a signed Meta CDN link that expires, so do not persist it: store the message id and resolve the media through `GET /v1/inbox/conversations/{conversationId}/messages/{messageId}/attachments/{index}?accountId={accountId}`, which re-mints it on demand. Every value that URL needs is already in this payload: `message.conversationId`, `message.platformMessageId`, `account.accountId`, and the attachment's zero-based position in this array.
22
25
  attr_accessor :url
23
26
 
24
27
  # Additional attachment metadata
@@ -28,6 +31,7 @@ module Zernio
28
31
  def self.attribute_map
29
32
  {
30
33
  :'type' => :'type',
34
+ :'original_type' => :'originalType',
31
35
  :'url' => :'url',
32
36
  :'payload' => :'payload'
33
37
  }
@@ -47,6 +51,7 @@ module Zernio
47
51
  def self.openapi_types
48
52
  {
49
53
  :'type' => :'String',
54
+ :'original_type' => :'String',
50
55
  :'url' => :'String',
51
56
  :'payload' => :'Object'
52
57
  }
@@ -80,6 +85,10 @@ module Zernio
80
85
  self.type = nil
81
86
  end
82
87
 
88
+ if attributes.key?(:'original_type')
89
+ self.original_type = attributes[:'original_type']
90
+ end
91
+
83
92
  if attributes.key?(:'url')
84
93
  self.url = attributes[:'url']
85
94
  else
@@ -142,6 +151,7 @@ module Zernio
142
151
  return true if self.equal?(o)
143
152
  self.class == o.class &&
144
153
  type == o.type &&
154
+ original_type == o.original_type &&
145
155
  url == o.url &&
146
156
  payload == o.payload
147
157
  end
@@ -155,7 +165,7 @@ module Zernio
155
165
  # Calculates hash code according to all attributes.
156
166
  # @return [Integer] Hash code
157
167
  def hash
158
- [type, url, payload].hash
168
+ [type, original_type, url, payload].hash
159
169
  end
160
170
 
161
171
  # Builds the object from hash
@@ -15,10 +15,13 @@ require 'time'
15
15
 
16
16
  module Zernio
17
17
  class WebhookPayloadMessageSentMessageAttachmentsInner < ApiModelBase
18
- # Attachment type (image, video, file, sticker, audio)
18
+ # Attachment type (image, video, file, sticker, audio, share)
19
19
  attr_accessor :type
20
20
 
21
- # Where to fetch the attachment. For outgoing messages this is the media URL as sent, so for WhatsApp it is the URL you supplied when publishing (WhatsApp sends media by link), not a Zernio endpoint, and it needs no Zernio credentials. Contrast the inbound direction: `message.received` attachment URLs on WhatsApp point at the authenticated `GET /v1/whatsapp/media/{mediaId}`.
21
+ # Instagram and Facebook only, and present only when it differs from `type`. Meta's own attachment type before Zernio normalized it. See the same field on message.received for the full mapping.
22
+ attr_accessor :original_type
23
+
24
+ # Where to fetch the attachment. For outgoing messages this is the media URL as sent, so for WhatsApp it is the URL you supplied when publishing (WhatsApp sends media by link), not a Zernio endpoint, and it needs no Zernio credentials. Contrast the inbound direction: `message.received` attachment URLs on WhatsApp point at the authenticated `GET /v1/whatsapp/media/{mediaId}`. As on `message.received`, webhook attachments carry no `refreshUrl`: that field is stamped only on the REST read. Resolve Instagram and Facebook media through `GET /v1/inbox/conversations/{conversationId}/messages/{messageId}/attachments/{index}?accountId={accountId}`.
22
25
  attr_accessor :url
23
26
 
24
27
  # Additional attachment metadata
@@ -28,6 +31,7 @@ module Zernio
28
31
  def self.attribute_map
29
32
  {
30
33
  :'type' => :'type',
34
+ :'original_type' => :'originalType',
31
35
  :'url' => :'url',
32
36
  :'payload' => :'payload'
33
37
  }
@@ -47,6 +51,7 @@ module Zernio
47
51
  def self.openapi_types
48
52
  {
49
53
  :'type' => :'String',
54
+ :'original_type' => :'String',
50
55
  :'url' => :'String',
51
56
  :'payload' => :'Object'
52
57
  }
@@ -80,6 +85,10 @@ module Zernio
80
85
  self.type = nil
81
86
  end
82
87
 
88
+ if attributes.key?(:'original_type')
89
+ self.original_type = attributes[:'original_type']
90
+ end
91
+
83
92
  if attributes.key?(:'url')
84
93
  self.url = attributes[:'url']
85
94
  else
@@ -142,6 +151,7 @@ module Zernio
142
151
  return true if self.equal?(o)
143
152
  self.class == o.class &&
144
153
  type == o.type &&
154
+ original_type == o.original_type &&
145
155
  url == o.url &&
146
156
  payload == o.payload
147
157
  end
@@ -155,7 +165,7 @@ module Zernio
155
165
  # Calculates hash code according to all attributes.
156
166
  # @return [Integer] Hash code
157
167
  def hash
158
- [type, url, payload].hash
168
+ [type, original_type, url, payload].hash
159
169
  end
160
170
 
161
171
  # Builds the object from hash
@@ -14,16 +14,21 @@ require 'date'
14
14
  require 'time'
15
15
 
16
16
  module Zernio
17
+ # **On this event the sender is your own business, not the person you are talking to.** `id` is the Zernio account id and `name`, `username` and `picture` are that connected account's own profile. Do not read these to name or update a contact: doing so on an echo relabels the customer's record with your business name. The other party is `conversation.participantId` / `participantName` / `participantUsername`, which are populated in both directions.
17
18
  class WebhookPayloadMessageSentMessageSender < ApiModelBase
19
+ # The Zernio account id of the connected account that sent the message, not a contact id.
18
20
  attr_accessor :id
19
21
 
20
22
  # Always omitted on this event: the sender is the business, not a contact. Use conversation.contactId to join back to the CRM Contact.
21
23
  attr_accessor :contact_id
22
24
 
25
+ # Display name of your connected account.
23
26
  attr_accessor :name
24
27
 
28
+ # Username of your connected account.
25
29
  attr_accessor :username
26
30
 
31
+ # Profile picture of your connected account.
27
32
  attr_accessor :picture
28
33
 
29
34
  # Attribute mapping from ruby-style variable name to JSON key.
@@ -11,5 +11,5 @@ Generator version: 7.19.0
11
11
  =end
12
12
 
13
13
  module Zernio
14
- VERSION = '0.0.808'
14
+ VERSION = '0.0.810'
15
15
  end
data/openapi.yaml CHANGED
@@ -3613,7 +3613,20 @@ components:
3613
3613
  properties:
3614
3614
  type:
3615
3615
  type: string
3616
- description: Attachment type (image, video, file, sticker, audio)
3616
+ description: Attachment type (image, video, file, sticker, audio, share)
3617
+ originalType:
3618
+ type: string
3619
+ description: |
3620
+ Instagram and Facebook only, and present only when it differs
3621
+ from `type`. Meta's own attachment type before Zernio normalized
3622
+ it: `ig_reel` and `reel` become `video`, while `ig_post`, `post`,
3623
+ `ig_story` and `story_mention` all become `share`.
3624
+
3625
+ Read it before rendering, because `type: "share"` alone is
3626
+ ambiguous. In particular a story mention arrives as
3627
+ `type: "share"` with `originalType: "story_mention"`; treating an
3628
+ unrecognized type as a generic document shows your agent
3629
+ "document received" for what is usually a lead.
3617
3630
  url:
3618
3631
  type: string
3619
3632
  description: |
@@ -3629,6 +3642,18 @@ components:
3629
3642
  - **Instagram / Facebook / Telegram**: a direct platform CDN link
3630
3643
  that needs no authentication and expires on the platform's own
3631
3644
  schedule.
3645
+
3646
+ **Webhook attachments carry no `refreshUrl`.** That field is
3647
+ stamped only when you read a message back over REST
3648
+ (`GET /v1/inbox/conversations/{conversationId}/messages`). On
3649
+ Instagram and Facebook the url above is a signed Meta CDN link
3650
+ that expires, so do not persist it: store the message id and
3651
+ resolve the media through
3652
+ `GET /v1/inbox/conversations/{conversationId}/messages/{messageId}/attachments/{index}?accountId={accountId}`,
3653
+ which re-mints it on demand. Every value that URL needs is
3654
+ already in this payload: `message.conversationId`,
3655
+ `message.platformMessageId`, `account.accountId`, and the
3656
+ attachment's zero-based position in this array.
3632
3657
  payload:
3633
3658
  type: object
3634
3659
  description: Additional attachment metadata
@@ -4031,7 +4056,10 @@ components:
4031
4056
  properties:
4032
4057
  type:
4033
4058
  type: string
4034
- description: Attachment type (image, video, file, sticker, audio)
4059
+ description: Attachment type (image, video, file, sticker, audio, share)
4060
+ originalType:
4061
+ type: string
4062
+ description: 'Instagram and Facebook only, and present only when it differs from `type`. Meta''s own attachment type before Zernio normalized it. See the same field on message.received for the full mapping.'
4035
4063
  url:
4036
4064
  type: string
4037
4065
  description: |
@@ -4041,24 +4069,42 @@ components:
4041
4069
  and it needs no Zernio credentials. Contrast the inbound direction:
4042
4070
  `message.received` attachment URLs on WhatsApp point at the
4043
4071
  authenticated `GET /v1/whatsapp/media/{mediaId}`.
4072
+
4073
+ As on `message.received`, webhook attachments carry no
4074
+ `refreshUrl`: that field is stamped only on the REST read. Resolve
4075
+ Instagram and Facebook media through
4076
+ `GET /v1/inbox/conversations/{conversationId}/messages/{messageId}/attachments/{index}?accountId={accountId}`.
4044
4077
  payload:
4045
4078
  type: object
4046
4079
  description: Additional attachment metadata
4047
4080
  sender:
4048
4081
  type: object
4049
4082
  required: [id]
4083
+ description: |
4084
+ **On this event the sender is your own business, not the person you
4085
+ are talking to.** `id` is the Zernio account id and `name`,
4086
+ `username` and `picture` are that connected account's own profile.
4087
+
4088
+ Do not read these to name or update a contact: doing so on an echo
4089
+ relabels the customer's record with your business name. The other
4090
+ party is `conversation.participantId` / `participantName` /
4091
+ `participantUsername`, which are populated in both directions.
4050
4092
  properties:
4051
4093
  id:
4052
4094
  type: string
4095
+ description: 'The Zernio account id of the connected account that sent the message, not a contact id.'
4053
4096
  contactId:
4054
4097
  type: string
4055
4098
  description: 'Always omitted on this event: the sender is the business, not a contact. Use conversation.contactId to join back to the CRM Contact.'
4056
4099
  name:
4057
4100
  type: string
4101
+ description: Display name of your connected account.
4058
4102
  username:
4059
4103
  type: string
4104
+ description: Username of your connected account.
4060
4105
  picture:
4061
4106
  type: string
4107
+ description: Profile picture of your connected account.
4062
4108
  sentAt:
4063
4109
  type: string
4064
4110
  format: date-time
@@ -17312,7 +17358,61 @@ paths:
17312
17358
  - name: redirect_url
17313
17359
  in: query
17314
17360
  schema: { type: string, format: uri }
17315
- description: Your custom redirect URL after connection completes. Accepts an http(s) URL, a custom app scheme for mobile deeplinks (e.g. myapp://callback), or a relative path. Result params are appended with the URL API, so an existing query string is preserved. Standard mode appends connected={platform}&profileId=X&accountId=Y&username=Z. Headless mode appends OAuth data params for platforms requiring selection (e.g. LinkedIn orgs, Facebook pages). If no selection is needed, the account is created directly and the redirect includes accountId.
17361
+ description: |
17362
+ Your custom redirect URL after connection completes. Accepts an http(s) URL, a custom app scheme for mobile deeplinks (e.g. myapp://callback), or a relative path. Result params are appended with the URL API, so an existing query string is preserved. Standard mode appends connected={platform}&profileId=X&accountId=Y&username=Z. Headless mode appends OAuth data params for platforms requiring selection (e.g. LinkedIn orgs, Facebook pages). If no selection is needed, the account is created directly and the redirect includes accountId.
17363
+
17364
+ On failure, the browser is sent to the same redirect_url with `error` and `platform` appended.
17365
+ `error` and `platform` are always present. `error_message`, `is_user_fixable`, `reason` and
17366
+ `dashboard_url` are conditional and must be treated as optional.
17367
+
17368
+ This list is NOT exhaustive and new values may be added at any time. Treat an unrecognized
17369
+ value as a generic failure rather than matching it exhaustively. Existing values are not
17370
+ renamed or removed without notice.
17371
+
17372
+ OAuth and callback:
17373
+ oauth_denied, invalid_callback, invalid_state, unsupported_platform, connection_failed,
17374
+ internal_error, token_exchange_failed, byok_config_error, personal_account_not_supported,
17375
+ missing_google_permissions, platform_requires_destination, reconnect_account_mismatch,
17376
+ invalid_request
17377
+
17378
+ Access and limits:
17379
+ profile_not_found, invalid_profile_id, access_denied, account_limit_exceeded,
17380
+ profile_limit_exceeded, payment_required
17381
+
17382
+ Destination selection:
17383
+ no_facebook_pages, facebook_pages_error, no_google_locations, google_locations_error,
17384
+ google_permission_denied, no_snapchat_public_profiles, snapchat_profiles_error,
17385
+ discord_no_guild, slack_no_team
17386
+
17387
+ WhatsApp:
17388
+ whatsapp_error, one_whatsapp_per_profile, whatsapp_number_already_connected,
17389
+ whatsapp_number_pinned_to_profile, connection_cancelled
17390
+
17391
+ Google Ads (platform=googleads):
17392
+ google_ads_auth_failed, google_ads_invalid_state, google_ads_config_error,
17393
+ google_ads_token_failed, google_ads_quota_exhausted, google_ads_callback_error
17394
+
17395
+ TikTok Ads (platform=tiktokads):
17396
+ tiktok_ads_auth_failed, tiktok_ads_invalid_state, tiktok_ads_access_denied,
17397
+ tiktok_ads_config_error, tiktok_ads_token_failed, tiktok_ads_account_not_found,
17398
+ tiktok_ads_callback_error
17399
+
17400
+ X Ads (platform=xads):
17401
+ x_ads_denied, x_ads_auth_failed, x_ads_config_error, x_ads_account_not_found,
17402
+ x_ads_state_error, x_ads_token_failed, x_ads_token_missing, x_ads_callback_error
17403
+
17404
+ Shopify (platform=shopify):
17405
+ shopify_auth_failed, shopify_config_error, shopify_invalid_state, shopify_invalid_hmac,
17406
+ shopify_invalid_shop, shopify_missing_scopes, shopify_callback_error
17407
+
17408
+ 1. On this endpoint every upstream OAuth error is collapsed into `oauth_denied`. The
17409
+ provider's own value (for example Meta's `access_denied`) is not forwarded. The dedicated
17410
+ ads flows below are different: they use their own denial slugs and `google_ads_auth_failed`
17411
+ and `tiktok_ads_auth_failed` may carry the provider's raw error string in `error_message`.
17412
+
17413
+ 2. On the tiktok and twitter ads flows `platform` carries the ads platform id
17414
+ (`tiktokads`, `xads`), not the value used in the request path. The googleads and shopify
17415
+ flows report `googleads` and `shopify`.
17316
17416
  - name: headless
17317
17417
  in: query
17318
17418
  schema: { type: boolean, default: false }
@@ -17417,7 +17517,24 @@ paths:
17417
17517
  description: |
17418
17518
  Unified ads connection endpoint. Creates a dedicated ads SocialAccount for the specified platform.
17419
17519
 
17420
- Same-token platforms (facebook, instagram, linkedin, pinterest): Creates an ads SocialAccount (metaads, linkedinads, pinterestads) with a copied OAuth token from the parent posting account. If the ads account already exists, returns alreadyConnected: true. No extra OAuth needed.
17520
+ Same-token platforms (facebook, instagram, linkedin, pinterest): the ads SocialAccount
17521
+ (metaads, linkedinads, pinterestads) reuses the OAuth token of the parent posting account,
17522
+ but only when an active parent exists and, for facebook and instagram, its stored token
17523
+ carries ads_management and ads_read (linkedin and pinterest need no extra scope). In that
17524
+ case no extra OAuth happens and the response is alreadyConnected: true. When no such parent
17525
+ exists, or the scopes are missing, the endpoint returns an authUrl and a full OAuth round
17526
+ trip is required. When a parent exists but carries no token usable for ad accounts, the call
17527
+ fails with 400 RECONNECT_REQUIRED. Independently of the branch, the call can return 403
17528
+ ADS_ADDON_REQUIRED without the ads add-on and 402 PAYMENT_REQUIRED when the billing gate is
17529
+ closed.
17530
+
17531
+ Meta Ads prerequisite: connecting Meta Ads (via facebook or instagram) requires a Facebook
17532
+ Page. Not because the ad account is read through a Page, but because both parent posting
17533
+ accounts are: the facebook flow only offers Pages you manage, and the instagram flow with
17534
+ loginMethod=facebook_login only offers Instagram accounts linked to one of those Pages.
17535
+ Without a Page there is no parent account to inherit a token from. A user who manages no
17536
+ Facebook Page cannot complete this connection, and the facebook flow ends with
17537
+ error=no_facebook_pages.
17421
17538
 
17422
17539
  Separate-token platforms (tiktok, twitter): Starts the platform-specific marketing API OAuth flow and creates an ads SocialAccount (tiktokads, xads) with its own token. If the ads account already exists, returns alreadyConnected: true.
17423
17540
  - tiktok: accountId is OPTIONAL. With accountId, the new tiktokads account links to that posting account (parentAccountId set) — Spark Ads + standalone ads using the posting TT_USER identity become available. Without accountId, ads-only mode kicks in: the new tiktokads account has parentAccountId=null and standalone ads use a synthetic CUSTOMIZED_USER ("Brand Identity"); Spark Ads are unavailable because TikTok requires a posting account for them. The Brand Identity is configured separately via PATCH /v1/connect/tiktok-ads (or inline on POST /v1/ads/create via the brandIdentity field).
@@ -17433,7 +17550,12 @@ paths:
17433
17550
  schema:
17434
17551
  type: string
17435
17552
  enum: [facebook, instagram, linkedin, tiktok, twitter, pinterest, googleads]
17436
- description: Platform to connect ads for. Only platforms with ads support are accepted.
17553
+ description: |
17554
+ Platform to connect ads for. Only platforms with ads support are accepted.
17555
+
17556
+ `instagram` requires an Instagram account connected with loginMethod=facebook_login whose
17557
+ token carries ads_management and ads_read. With an account connected through the default
17558
+ instagram_login flow no ads account can be created; do not use this value for those accounts.
17437
17559
  - name: profileId
17438
17560
  in: query
17439
17561
  required: true
@@ -17458,8 +17580,12 @@ paths:
17458
17580
  `tiktok`, `twitter` and `googleads` land on the URL unchanged, while the
17459
17581
  same-token platforms (`facebook`, `instagram`, `linkedin`, `pinterest`)
17460
17582
  append `connected`, `profileId`, `accountId`, `username` and, on API-key
17461
- calls, `connect_token`. On failure every platform appends error details,
17462
- starting with `error` and `platform`. When omitted, the browser lands on
17583
+ calls, `connect_token`. On failure the same error contract applies as on
17584
+ GET /v1/connect/{platform}: `error` and `platform` are always appended,
17585
+ other params are optional, and the value list there is not exhaustive.
17586
+ Note that on the tiktok, twitter and googleads flows `platform` carries
17587
+ the ads platform id (`tiktokads`, `xads`, `googleads`), not the value
17588
+ used in the request path. When omitted, the browser lands on
17463
17589
  the Zernio dashboard.
17464
17590
  - name: headless
17465
17591
  in: query
@@ -26734,6 +26860,9 @@ paths:
26734
26860
  properties:
26735
26861
  id: { type: string }
26736
26862
  type: { type: string, enum: [image, video, audio, file, sticker, share] }
26863
+ originalType:
26864
+ type: string
26865
+ description: 'Instagram and Facebook only, and present only when it differs from `type`. Meta''s own type before normalization: `ig_reel` and `reel` become `video`, while `ig_post`, `post`, `ig_story` and `story_mention` become `share`. A story mention is `type: "share"` with `originalType: "story_mention"`; render on this field, since `share` alone is ambiguous.'
26737
26866
  url:
26738
26867
  type: string
26739
26868
  description: 'Direct media link. On Instagram and Facebook this is a signed Meta CDN url that EXPIRES: use it now, do not store it. Persist `refreshUrl` instead.'
@@ -28156,7 +28285,16 @@ paths:
28156
28285
  and stops working later. This endpoint checks the stored url and, when it
28157
28286
  has gone stale, re-mints the message's media from Meta and persists it
28158
28287
  before answering. The message id never expires, so this URL is the one to
28159
- store — it is returned on each attachment as `refreshUrl`.
28288
+ store. It is returned ready-made on each attachment as `refreshUrl` when
28289
+ you read a message over REST.
28290
+
28291
+ **Webhook payloads do not carry `refreshUrl`**, so a webhook-driven
28292
+ integration builds this URL itself. Every piece is in the event:
28293
+ `message.conversationId`, `message.platformMessageId`, the attachment's
28294
+ zero-based position, and `account.accountId`. Note that **`accountId` is a
28295
+ required query parameter**; omitting it returns `400`
28296
+ `missing_required_field`, which is the same requirement
28297
+ `GET /v1/whatsapp/media/{mediaId}` has.
28160
28298
 
28161
28299
  By default it responds `302` to the live media url, so it can be used
28162
28300
  directly as an `<img src>` on a browser session. API-key integrators
@@ -28188,7 +28326,7 @@ paths:
28188
28326
  in: query
28189
28327
  required: true
28190
28328
  schema: { type: string }
28191
- description: Social account ID
28329
+ description: 'Social account ID. Required: without it the request returns 400 missing_required_field.'
28192
28330
  - name: format
28193
28331
  in: query
28194
28332
  required: false
@@ -84,12 +84,12 @@ describe 'ConnectApi' do
84
84
 
85
85
  # unit tests for connect_ads
86
86
  # Connect ads for a platform
87
- # Unified ads connection endpoint. Creates a dedicated ads SocialAccount for the specified platform. Same-token platforms (facebook, instagram, linkedin, pinterest): Creates an ads SocialAccount (metaads, linkedinads, pinterestads) with a copied OAuth token from the parent posting account. If the ads account already exists, returns alreadyConnected: true. No extra OAuth needed. Separate-token platforms (tiktok, twitter): Starts the platform-specific marketing API OAuth flow and creates an ads SocialAccount (tiktokads, xads) with its own token. If the ads account already exists, returns alreadyConnected: true. - tiktok: accountId is OPTIONAL. With accountId, the new tiktokads account links to that posting account (parentAccountId set) — Spark Ads + standalone ads using the posting TT_USER identity become available. Without accountId, ads-only mode kicks in: the new tiktokads account has parentAccountId&#x3D;null and standalone ads use a synthetic CUSTOMIZED_USER (\&quot;Brand Identity\&quot;); Spark Ads are unavailable because TikTok requires a posting account for them. The Brand Identity is configured separately via PATCH /v1/connect/tiktok-ads (or inline on POST /v1/ads/create via the brandIdentity field). - twitter (X Ads): accountId is REQUIRED. There&#39;s no ads-only mode — tweets need to be authored by a real X user. Standalone platforms (googleads): Starts the Google Ads OAuth flow and creates a standalone ads SocialAccount (googleads) with no parent. If the account already exists, returns alreadyConnected: true. Ads accounts appear as regular SocialAccount documents with ads platform values (e.g., metaads, tiktokads) in GET /v1/accounts.
88
- # @param platform Platform to connect ads for. Only platforms with ads support are accepted.
87
+ # Unified ads connection endpoint. Creates a dedicated ads SocialAccount for the specified platform. Same-token platforms (facebook, instagram, linkedin, pinterest): the ads SocialAccount (metaads, linkedinads, pinterestads) reuses the OAuth token of the parent posting account, but only when an active parent exists and, for facebook and instagram, its stored token carries ads_management and ads_read (linkedin and pinterest need no extra scope). In that case no extra OAuth happens and the response is alreadyConnected: true. When no such parent exists, or the scopes are missing, the endpoint returns an authUrl and a full OAuth round trip is required. When a parent exists but carries no token usable for ad accounts, the call fails with 400 RECONNECT_REQUIRED. Independently of the branch, the call can return 403 ADS_ADDON_REQUIRED without the ads add-on and 402 PAYMENT_REQUIRED when the billing gate is closed. Meta Ads prerequisite: connecting Meta Ads (via facebook or instagram) requires a Facebook Page. Not because the ad account is read through a Page, but because both parent posting accounts are: the facebook flow only offers Pages you manage, and the instagram flow with loginMethod&#x3D;facebook_login only offers Instagram accounts linked to one of those Pages. Without a Page there is no parent account to inherit a token from. A user who manages no Facebook Page cannot complete this connection, and the facebook flow ends with error&#x3D;no_facebook_pages. Separate-token platforms (tiktok, twitter): Starts the platform-specific marketing API OAuth flow and creates an ads SocialAccount (tiktokads, xads) with its own token. If the ads account already exists, returns alreadyConnected: true. - tiktok: accountId is OPTIONAL. With accountId, the new tiktokads account links to that posting account (parentAccountId set) — Spark Ads + standalone ads using the posting TT_USER identity become available. Without accountId, ads-only mode kicks in: the new tiktokads account has parentAccountId&#x3D;null and standalone ads use a synthetic CUSTOMIZED_USER (\&quot;Brand Identity\&quot;); Spark Ads are unavailable because TikTok requires a posting account for them. The Brand Identity is configured separately via PATCH /v1/connect/tiktok-ads (or inline on POST /v1/ads/create via the brandIdentity field). - twitter (X Ads): accountId is REQUIRED. There&#39;s no ads-only mode — tweets need to be authored by a real X user. Standalone platforms (googleads): Starts the Google Ads OAuth flow and creates a standalone ads SocialAccount (googleads) with no parent. If the account already exists, returns alreadyConnected: true. Ads accounts appear as regular SocialAccount documents with ads platform values (e.g., metaads, tiktokads) in GET /v1/accounts.
88
+ # @param platform Platform to connect ads for. Only platforms with ads support are accepted. &#x60;instagram&#x60; requires an Instagram account connected with loginMethod&#x3D;facebook_login whose token carries ads_management and ads_read. With an account connected through the default instagram_login flow no ads account can be created; do not use this value for those accounts.
89
89
  # @param profile_id Your Zernio profile ID
90
90
  # @param [Hash] opts the optional parameters
91
91
  # @option opts [String] :account_id Existing SocialAccount ID. Required for &#x60;twitter&#x60; (X Ads). Optional for &#x60;tiktok&#x60; — omit to enter ads-only mode (no TikTok posting account linked; ad creation uses a Brand Identity instead of a TT_USER). Ignored for same-token (&#x60;facebook&#x60;, &#x60;instagram&#x60;, &#x60;linkedin&#x60;, &#x60;pinterest&#x60;) and standalone (&#x60;googleads&#x60;) platforms.
92
- # @option opts [String] :redirect_url Custom URL the browser is sent to once the OAuth flow finishes. Honored on every ads platform, including the separate-token (&#x60;tiktok&#x60;, &#x60;twitter&#x60;) and standalone (&#x60;googleads&#x60;) flows. Accepts an http(s) URL, a custom app scheme for mobile deeplinks (e.g. myapp://callback), or a relative path. On success &#x60;tiktok&#x60;, &#x60;twitter&#x60; and &#x60;googleads&#x60; land on the URL unchanged, while the same-token platforms (&#x60;facebook&#x60;, &#x60;instagram&#x60;, &#x60;linkedin&#x60;, &#x60;pinterest&#x60;) append &#x60;connected&#x60;, &#x60;profileId&#x60;, &#x60;accountId&#x60;, &#x60;username&#x60; and, on API-key calls, &#x60;connect_token&#x60;. On failure every platform appends error details, starting with &#x60;error&#x60; and &#x60;platform&#x60;. When omitted, the browser lands on the Zernio dashboard.
92
+ # @option opts [String] :redirect_url Custom URL the browser is sent to once the OAuth flow finishes. Honored on every ads platform, including the separate-token (&#x60;tiktok&#x60;, &#x60;twitter&#x60;) and standalone (&#x60;googleads&#x60;) flows. Accepts an http(s) URL, a custom app scheme for mobile deeplinks (e.g. myapp://callback), or a relative path. On success &#x60;tiktok&#x60;, &#x60;twitter&#x60; and &#x60;googleads&#x60; land on the URL unchanged, while the same-token platforms (&#x60;facebook&#x60;, &#x60;instagram&#x60;, &#x60;linkedin&#x60;, &#x60;pinterest&#x60;) append &#x60;connected&#x60;, &#x60;profileId&#x60;, &#x60;accountId&#x60;, &#x60;username&#x60; and, on API-key calls, &#x60;connect_token&#x60;. On failure the same error contract applies as on GET /v1/connect/{platform}: &#x60;error&#x60; and &#x60;platform&#x60; are always appended, other params are optional, and the value list there is not exhaustive. Note that on the tiktok, twitter and googleads flows &#x60;platform&#x60; carries the ads platform id (&#x60;tiktokads&#x60;, &#x60;xads&#x60;, &#x60;googleads&#x60;), not the value used in the request path. When omitted, the browser lands on the Zernio dashboard.
93
93
  # @option opts [Boolean] :headless Enable headless mode (same-token platforms only)
94
94
  # @option opts [Boolean] :force Force a fresh OAuth even when an account already exists. Normally the endpoint returns &#x60;alreadyConnected: true&#x60; whenever a connected account is found, keying off its active state rather than token liveness. Set &#x60;force&#x3D;true&#x60; to bypass that and always receivean &#x60;authUrl&#x60;. Completing the returned OAuth refreshes the stored token on the existing posting and ads accounts in place.
95
95
  # @option opts [String] :ad_account_id Scope ad sync to a single platform ad account. Without this param, sync covers every ad account the connected token can see. Supported on &#x60;facebook&#x60;/&#x60;instagram&#x60; (Meta, &#x60;act_&lt;digits&gt;&#x60;), &#x60;linkedin&#x60; (bare numeric sponsored-account id), &#x60;googleads&#x60; (bare customer id digits) and &#x60;twitter&#x60; (X Ads, base36 account id). &#x60;tiktok&#x60; scopes advertisers at OAuth and &#x60;pinterest&#x60; has no ads discovery, so both ignore it. Meta ids are additionally validated against the connected token; unreachable IDs return 400. Setting a scope also removes already synced ads from de-scoped ad accounts. For multiple accounts use &#x60;adAccountIds&#x60; instead.
@@ -204,7 +204,7 @@ describe 'ConnectApi' do
204
204
  # @param platform Social media platform to connect
205
205
  # @param profile_id Your Zernio profile ID (get from /v1/profiles). For WhatsApp, a Zernio-provisioned number can only be connected on the profile it was provisioned to; connecting from any other profile is rejected with a 409.
206
206
  # @param [Hash] opts the optional parameters
207
- # @option opts [String] :redirect_url Your custom redirect URL after connection completes. Accepts an http(s) URL, a custom app scheme for mobile deeplinks (e.g. myapp://callback), or a relative path. Result params are appended with the URL API, so an existing query string is preserved. Standard mode appends connected&#x3D;{platform}&amp;profileId&#x3D;X&amp;accountId&#x3D;Y&amp;username&#x3D;Z. Headless mode appends OAuth data params for platforms requiring selection (e.g. LinkedIn orgs, Facebook pages). If no selection is needed, the account is created directly and the redirect includes accountId.
207
+ # @option opts [String] :redirect_url Your custom redirect URL after connection completes. Accepts an http(s) URL, a custom app scheme for mobile deeplinks (e.g. myapp://callback), or a relative path. Result params are appended with the URL API, so an existing query string is preserved. Standard mode appends connected&#x3D;{platform}&amp;profileId&#x3D;X&amp;accountId&#x3D;Y&amp;username&#x3D;Z. Headless mode appends OAuth data params for platforms requiring selection (e.g. LinkedIn orgs, Facebook pages). If no selection is needed, the account is created directly and the redirect includes accountId. On failure, the browser is sent to the same redirect_url with &#x60;error&#x60; and &#x60;platform&#x60; appended. &#x60;error&#x60; and &#x60;platform&#x60; are always present. &#x60;error_message&#x60;, &#x60;is_user_fixable&#x60;, &#x60;reason&#x60; and &#x60;dashboard_url&#x60; are conditional and must be treated as optional. This list is NOT exhaustive and new values may be added at any time. Treat an unrecognized value as a generic failure rather than matching it exhaustively. Existing values are not renamed or removed without notice. OAuth and callback: oauth_denied, invalid_callback, invalid_state, unsupported_platform, connection_failed, internal_error, token_exchange_failed, byok_config_error, personal_account_not_supported, missing_google_permissions, platform_requires_destination, reconnect_account_mismatch, invalid_request Access and limits: profile_not_found, invalid_profile_id, access_denied, account_limit_exceeded, profile_limit_exceeded, payment_required Destination selection: no_facebook_pages, facebook_pages_error, no_google_locations, google_locations_error, google_permission_denied, no_snapchat_public_profiles, snapchat_profiles_error, discord_no_guild, slack_no_team WhatsApp: whatsapp_error, one_whatsapp_per_profile, whatsapp_number_already_connected, whatsapp_number_pinned_to_profile, connection_cancelled Google Ads (platform&#x3D;googleads): google_ads_auth_failed, google_ads_invalid_state, google_ads_config_error, google_ads_token_failed, google_ads_quota_exhausted, google_ads_callback_error TikTok Ads (platform&#x3D;tiktokads): tiktok_ads_auth_failed, tiktok_ads_invalid_state, tiktok_ads_access_denied, tiktok_ads_config_error, tiktok_ads_token_failed, tiktok_ads_account_not_found, tiktok_ads_callback_error X Ads (platform&#x3D;xads): x_ads_denied, x_ads_auth_failed, x_ads_config_error, x_ads_account_not_found, x_ads_state_error, x_ads_token_failed, x_ads_token_missing, x_ads_callback_error Shopify (platform&#x3D;shopify): shopify_auth_failed, shopify_config_error, shopify_invalid_state, shopify_invalid_hmac, shopify_invalid_shop, shopify_missing_scopes, shopify_callback_error 1. On this endpoint every upstream OAuth error is collapsed into &#x60;oauth_denied&#x60;. The provider&#39;s own value (for example Meta&#39;s &#x60;access_denied&#x60;) is not forwarded. The dedicated ads flows below are different: they use their own denial slugs and &#x60;google_ads_auth_failed&#x60; and &#x60;tiktok_ads_auth_failed&#x60; may carry the provider&#39;s raw error string in &#x60;error_message&#x60;. 2. On the tiktok and twitter ads flows &#x60;platform&#x60; carries the ads platform id (&#x60;tiktokads&#x60;, &#x60;xads&#x60;), not the value used in the request path. The googleads and shopify flows report &#x60;googleads&#x60; and &#x60;shopify&#x60;.
208
208
  # @option opts [Boolean] :headless When true, the user is redirected to your redirect_url with raw OAuth data (code, state) instead of Zernio&#39;s default account selection UI. Use this to build a custom connect experience.
209
209
  # @option opts [String] :login_method Instagram only. Which of the two Instagram connection methods to use. Ignored for every other platform. &#x60;instagram_login&#x60; (the default, and what you get if you omit this): the Instagram Login dialog. The user authorizes their Instagram professional account directly, no Facebook Page required. &#x60;facebook_login&#x60;: the Facebook Login dialog, i.e. \&quot;Instagram API with Facebook Login\&quot;. The user authorizes a Facebook Page that has a linked Instagram professional account, and every API call for that account then runs through the Page. Use this when the customer manages Instagram through a Page and expects the Facebook consent screen. Because the user has to pick which Page to connect, the callback continues at the account-selection step, &#x60;/v1/connect/instagram/select-account&#x60;. &#x60;facebook_login&#x60; supports &#x60;headless&#x3D;true&#x60; like the other selection platforms: the callback redirects to your &#x60;redirect_url&#x60; with &#x60;profileId&#x60;, &#x60;tempToken&#x60;, &#x60;platform&#x3D;instagram&#x60;, &#x60;step&#x3D;select_account&#x60; and &#x60;connect_token&#x60;, which you pass into the select-account endpoints to finish. The default &#x60;instagram_login&#x60; has no selection step, so it connects the account directly.
210
210
  # @option opts [String] :onboarding WhatsApp only. Ignored for every other platform. Controls which screen Meta&#39;s Embedded Signup popup shows. If omitted, the connection defaults to coexistence (same as &#x60;business_app&#x60; below), preserving existing behavior for numbers already on the WhatsApp Business app. &#x60;api&#x60;: standard Embedded Signup, showing Meta&#39;s WABA/number picker. Use this to connect a phone number already on Cloud API elsewhere. &#x60;business_app&#x60;: coexistence, i.e. &#39;Connect existing WhatsApp Business app&#39; (a number shared between Cloud API and the consumer WhatsApp Business app).
@@ -117,11 +117,11 @@ describe 'MessagesApi' do
117
117
 
118
118
  # unit tests for get_message_attachment
119
119
  # Resolve message attachment
120
- # Resolve one attachment on a message to a media url that works right now. Instagram and Facebook sign DM media urls per request and expire them, so the &#x60;url&#x60; on a message is a snapshot: it works when you read the message and stops working later. This endpoint checks the stored url and, when it has gone stale, re-mints the message&#39;s media from Meta and persists it before answering. The message id never expires, so this URL is the one to store — it is returned on each attachment as &#x60;refreshUrl&#x60;. By default it responds &#x60;302&#x60; to the live media url, so it can be used directly as an &#x60;&lt;img src&gt;&#x60; on a browser session. API-key integrators should pass &#x60;?format&#x3D;json&#x60; and read &#x60;url&#x60; off the body, since a browser cannot attach an Authorization header to an image request. Only Instagram and Facebook media can be re-minted. On other platforms the stored url is returned as-is when it still resolves, and &#x60;404&#x60; otherwise.
120
+ # Resolve one attachment on a message to a media url that works right now. Instagram and Facebook sign DM media urls per request and expire them, so the &#x60;url&#x60; on a message is a snapshot: it works when you read the message and stops working later. This endpoint checks the stored url and, when it has gone stale, re-mints the message&#39;s media from Meta and persists it before answering. The message id never expires, so this URL is the one to store. It is returned ready-made on each attachment as &#x60;refreshUrl&#x60; when you read a message over REST. **Webhook payloads do not carry &#x60;refreshUrl&#x60;**, so a webhook-driven integration builds this URL itself. Every piece is in the event: &#x60;message.conversationId&#x60;, &#x60;message.platformMessageId&#x60;, the attachment&#39;s zero-based position, and &#x60;account.accountId&#x60;. Note that **&#x60;accountId&#x60; is a required query parameter**; omitting it returns &#x60;400&#x60; &#x60;missing_required_field&#x60;, which is the same requirement &#x60;GET /v1/whatsapp/media/{mediaId}&#x60; has. By default it responds &#x60;302&#x60; to the live media url, so it can be used directly as an &#x60;&lt;img src&gt;&#x60; on a browser session. API-key integrators should pass &#x60;?format&#x3D;json&#x60; and read &#x60;url&#x60; off the body, since a browser cannot attach an Authorization header to an image request. Only Instagram and Facebook media can be re-minted. On other platforms the stored url is returned as-is when it still resolves, and &#x60;404&#x60; otherwise.
121
121
  # @param conversation_id The conversation ID (Zernio id or platform conversation id)
122
122
  # @param message_id The message id as returned by the list-messages endpoint (the platform message id)
123
123
  # @param index Zero-based position of the attachment in the message&#39;s attachments array
124
- # @param account_id Social account ID
124
+ # @param account_id Social account ID. Required: without it the request returns 400 missing_required_field.
125
125
  # @param [Hash] opts the optional parameters
126
126
  # @option opts [String] :format &#x60;redirect&#x60; (default) answers 302 to the media; &#x60;json&#x60; returns the url in the body
127
127
  # @return [GetMessageAttachment200Response]
@@ -43,6 +43,12 @@ describe Zernio::GetInboxConversationMessages200ResponseMessagesInnerAttachments
43
43
  end
44
44
  end
45
45
 
46
+ describe 'test attribute "original_type"' do
47
+ it 'should work' do
48
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
49
+ end
50
+ end
51
+
46
52
  describe 'test attribute "url"' do
47
53
  it 'should work' do
48
54
  # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
@@ -33,6 +33,12 @@ describe Zernio::WebhookPayloadMessageMessageAttachmentsInner do
33
33
  end
34
34
  end
35
35
 
36
+ describe 'test attribute "original_type"' 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
+
36
42
  describe 'test attribute "url"' do
37
43
  it 'should work' do
38
44
  # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
@@ -33,6 +33,12 @@ describe Zernio::WebhookPayloadMessageSentMessageAttachmentsInner do
33
33
  end
34
34
  end
35
35
 
36
+ describe 'test attribute "original_type"' 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
+
36
42
  describe 'test attribute "url"' do
37
43
  it 'should work' do
38
44
  # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zernio-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.808
4
+ version: 0.0.810
5
5
  platform: ruby
6
6
  authors:
7
7
  - OpenAPI-Generator