late-sdk 0.0.1588 → 0.0.1589

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: c5dd4e7efb3dc1ca954156e54e9bbaf23fdd8605d7a4aeda07d27e2fbd4cf796
4
- data.tar.gz: 5da2c89e9efafb02f48d13be3eafce2c273eabd9908874a51ed7d8457bcfa6f1
3
+ metadata.gz: 14cf30449822b32deb95a556de2ff4f2597c20dd35e85c6ec306092cce6f0740
4
+ data.tar.gz: 8975dc864d3fcf347c9fa26996519613cf24a25fedc1c2f47d4a167156e48ccf
5
5
  SHA512:
6
- metadata.gz: a48cd8a159a19d9dab38ea1ea9dd070cd31c26acd717d7c0e4b6a68826edf777a10de99168714b54241cdebbdbca2ff81554d1e6a1417348fef13e3d44688a07
7
- data.tar.gz: 82557df489c102c17101a67541ba3f0626993eb81d213e0097d82ecfb1f9ceae5e17fdeb69820fb7386c792b3ecec898b12c71281fdd74f62319aac3a02647df
6
+ metadata.gz: 304107c3911fd641885934edeb6d2ac2a8cbbfccb453dcf64f44aa7b2e9ab778e0e80a465f5db9a2ae252328c42dd3afc6413b9786b13098920f06ab9ada9b0c
7
+ data.tar.gz: 057573d0f42ddeaa3442ba6fd23cf03b41a38b58a9e9462fc0298f90b86fe27fbf34f3fb6c9028e5c2feb5724fb4aee402c1a29b1cf15109c89d38742528c8e5
@@ -6,7 +6,7 @@
6
6
  | ---- | ---- | ----------- | ----- |
7
7
  | **text** | **String** | Required on every platform except WhatsApp (which sends `template`) and an SMS broadcast that carries attachments. | [optional] |
8
8
  | **attachments** | [**Array<CreateBroadcastRequestMessageAttachmentsInner>**](CreateBroadcastRequestMessageAttachmentsInner.md) | SMS only: sent as MMS media, one media_url per attachment. Each url must be public http(s); JPEG, PNG, GIF, WEBP, MP4 or 3GPP under 1 MB (checked at create when the host answers a HEAD request; Telnyx enforces the 1 MB total per message at send). | [optional] |
9
- | **message_tag** | **String** | Instagram and Facebook only. Meta message tag sent with every recipient message (messaging_type MESSAGE_TAG) so the broadcast can reach people outside the 24h window. Instagram accepts HUMAN_AGENT only. Rejected with a 400 on any other platform. | [optional] |
9
+ | **message_tag** | **String** | Not usable: a broadcast only reaches people within the 24h window. HUMAN_AGENT is rejected with a 400 because it is only for replies typed by a person, and Meta retired the other tags. | [optional] |
10
10
 
11
11
  ## Example
12
12
 
@@ -25,7 +25,7 @@
25
25
  | **interactive** | [**SendInboxMessageRequestInteractive**](SendInboxMessageRequestInteractive.md) | | [optional] |
26
26
  | **reply_markup** | [**SendInboxMessageRequestReplyMarkup**](SendInboxMessageRequestReplyMarkup.md) | | [optional] |
27
27
  | **messaging_type** | **String** | Facebook messaging type. Required when using messageTag. | [optional] |
28
- | **message_tag** | **String** | Facebook message tag for messaging outside 24h window. Requires messagingType MESSAGE_TAG. Instagram only supports HUMAN_AGENT. | [optional] |
28
+ | **message_tag** | **String** | Facebook and Instagram. To reply after the 24h window, send HUMAN_AGENT with messagingType MESSAGE_TAG: it works up to 7 days after the person's last message, for replies typed by a person only (Meta does not allow it on automated messages). Meta retired the other tags, so they fail. | [optional] |
29
29
  | **reply_to** | **String** | Platform message ID to quote-reply to. For WhatsApp, pass the wamid; for Telegram, the Telegram message ID (delivered as message.platformMessageId on webhooks, and as `id` on each entry of the list-messages endpoint). On Slack it threads the reply (thread_ts) instead of quoting. Instagram and Facebook Messenger do not support send-side quote replies: the message is sent without a quote and the successful response includes a warnings entry with code ignored_field and param replyTo. Other platforms without send-side reply support ignore this field. | [optional] |
30
30
  | **location** | [**SendInboxMessageRequestLocation**](SendInboxMessageRequestLocation.md) | | [optional] |
31
31
  | **contacts** | [**Array<SendInboxMessageRequestContactsInner>**](SendInboxMessageRequestContactsInner.md) | WhatsApp-only. Send one or more contact cards. | [optional] |
data/docs/WorkflowNode.md CHANGED
@@ -6,7 +6,7 @@
6
6
  | ---- | ---- | ----------- | ----- |
7
7
  | **id** | **String** | Stable node id referenced by edges | |
8
8
  | **type** | **String** | Node kind. The 17 supported types break into four groups: messaging (send_message), control flow (trigger, condition, delay, wait_for_reply, a_b_split, end), data ops (set_variable, set_field, add_tag, remove_tag, enroll_sequence), integrations (webhook, hubspot_upsert_contact, ai, handoff, start_call). | |
9
- | **config** | **Hash<String, Object>** | Type-specific settings. All string fields support `{{variable}}` interpolation against the run's variable bag (resolved at execution time). **trigger**: `{ triggerType: inbound_message|api_call|whatsapp_event|referral|story_mention|comment|reaction|lead_received, keywords:[string], matchType: any|contains|exact|regex, onlyFirstMessage:boolean, eventType: message_sent|message_delivered|message_read|message_failed|reaction, referral:{ ref, matchType: exact|prefix|any }, reaction:{ emojis:[string] }, comment:{ keywords:[string], matchType: any|contains|exact|regex, platformPostId }, leadReceived:{ formIds:[string], pageAccountIds:[string], consentCheckboxKey, defaultCountry, allowCrossProfile:boolean }, cooldownHours:int (1-720) }`. Default `triggerType` is `inbound_message` for legacy nodes. A workflow starts only on events of its own trigger type: `inbound_message` on a message, `referral` on an ig.me / m.me / click-to-message ad referral (standalone, or the first message carrying one; the two are deduplicated per conversation within 60 seconds), `story_mention` on an Instagram story mention, `reaction` on a reaction (Instagram, Facebook, WhatsApp, Telegram groups), `comment` on an Instagram or Facebook comment (the run starts with no conversation and its first `send_message`, which must be text (with optional buttons or quick replies) or cards and must follow the trigger directly (checked on save; on some Instagram accounts Meta refuses buttons and cards to commenters who do not follow the account), is sent as a private reply to the comment; the run then continues in the conversation that reply opens; when an active comment automation's keywords match the comment, the automation answers and the workflow does not start), `whatsapp_event` on a WhatsApp status of a message we sent (filtered by `eventType`), `api_call` only via `POST /v1/workflows/{workflowId}/trigger`, and `lead_received` (WhatsApp workflows only) when a Meta lead ad form is submitted. A `lead_received` trigger needs `leadReceived.consentCheckboxKey` and at least one of `formIds` or `pageAccountIds`; a form scope wins over a Page scope, then the earliest activated workflow. It starts only for leads submitted in the last hour and after the workflow was activated, whose consent checkbox (the form's custom disclaimer, see `POST /v1/ads/lead-forms`) is ticked, and whose phone number parses to a valid international number (`defaultCountry`, ISO 3166 alpha-2, defaults to the country of the workflow's WhatsApp number); otherwise the lead is marked `unreachable`. The Page and the WhatsApp number must be in the same profile unless `allowCrossProfile` is true. Every send or call reached first from the trigger must be a WhatsApp template (checked on save). `referral.matchType` defaults to `any`. `cooldownHours` (inbound_message, referral, story_mention, reaction, whatsapp_event and lead_received, where it defaults to 24) stops the same contact from starting the workflow again inside the window. A `whatsapp_event` workflow never starts on the status of a message a workflow, sequence or comment automation sent. A redelivered platform event never starts the same workflow twice. **Variables** available from the start of every run (absent values are `''`): `lastMessage`, `inboundText`, `triggerText`, `conversationId`, `contact.name`, `contact.phone`, `contact.handle`, `contact.tags` (array), `contact.fields` (the contact's custom fields object), `contact.lastInteractionAt` (ISO date), `contact.lastInteractionHoursAgo` (number), `contact.isFollower` (Instagram, from the stored profile: true, false or `''` when unknown), `referral.ref`, `referral.source`, `referral.type`, `referral.adId`, `referral.adTitle` (the ad title or headline Meta sent), `referral.adName` (the synced ad's name, else `referral.adTitle`), `referral.campaignName` (the synced ad's campaign), `postback.payload`, `postback.title`, `quickReply.payload`, `quickReply.title`, `story.id`, `story.url`, `comment.id`, `comment.text`, `comment.platformPostId`, `reaction.emoji`, `reaction.action` (added|removed). `api_call` runs also get the request's `variables`, merged over these. `lead_received` runs also get `lead.id`, `lead.leadgenId`, `lead.formId`, `lead.formName`, `lead.adId`, `lead.adsetId`, `lead.campaignId` and every form answer by its key (`lead.full_name`, `lead.email`, `lead.phone_number`). Template `variableMapping` entries with `field: custom` interpolate `{{...}}` in `customValue`. An array or object interpolated into text renders as JSON. **send_message**: `{ messageType: text|template|media|interactive|cards, text, template, media:{mediaType:image|video|audio|document, url,caption}, interactive, buttons, quickReplies, messageTag }`. `template` is `{name,language,variableMapping}` for `messageType: template` and `{ type: generic, elements:[{ title, subtitle, imageUrl, buttons }] }` (1 to 10 cards) for `messageType: cards`. `template` and `interactive` are WhatsApp-only. `interactive.type` is inferred from the payload shape when omitted; payloads with neither `type` nor an inferable shape are rejected. Facebook and Instagram only (rejected with a 400 on other platforms; WhatsApp keeps `interactive`): `cards`, plus `buttons` on `text` (cards carry their own buttons) and `quickReplies` / `messageTag` on `text`, `media` and `cards`. `media` takes no `buttons` (a 400 at save). `buttons:[{ type: url|postback|phone, title, url, payload, phone, workflowId }]` (1 to 3, text only and the text then 640 characters at most, sent as Meta's button_template, `phone` Facebook-only, not inside cards), `quickReplies:[{ title, payload, imageUrl, workflowId }]` (1 to 13, not combined with `buttons`) and `messageTag: HUMAN_AGENT|CONFIRMED_EVENT_UPDATE|POST_PURCHASE_UPDATE|ACCOUNT_UPDATE` (Instagram accepts only `HUMAN_AGENT`). Titles are capped at 20 characters (80 for card titles and subtitles). A postback button or quick reply with no `payload` gets `zernio:workflow:<this workflow id>`, so a tap answers this workflow's pending `wait_for_reply` or restarts it; with `workflowId` (a 24-hex workflow id, not combined with `payload`) the tap starts that workflow instead. **wait_for_reply**: `{ timeoutMinutes:int (max 43200), saveAs:string }`. Resume via the `'reply'` edge on inbound, or `'timeout'` edge after `timeoutMinutes` of silence. On Facebook and Instagram a button tap sets `{{postback.payload}}` / `{{postback.title}}` and a quick reply tap sets `{{quickReply.payload}}` / `{{quickReply.title}}`; each reply clears the previous tap. **condition**: `{ rules:[{ id, variable, operator: equals|not_equals|contains|not_contains|starts_with|ends_with|exists|not_exists|matches|greater_than|less_than|greater_or_equal|less_or_equal|before|after|has_tag|not_has_tag|is_true|is_false, value }] }`. First matching rule takes its `id` as the sourceHandle; otherwise `'default'`. Text operators compare case-insensitively. `greater_than`, `less_than`, `greater_or_equal` and `less_or_equal` compare numbers (a non-numeric side is false); `before` and `after` compare ISO dates; `has_tag` and `not_has_tag` test whether an array variable (such as `contact.tags`) contains `value`; `is_true` and `is_false` take no value. **set_variable**: `{ assignments:[{ name, value }] }`. Run-scoped (lives only for this execution; use `set_field` for persistent values). **delay**: `{ delayMinutes:int (max 43200) }`. Suspends the run, resumes via timer. **webhook**: `{ url, method: GET|POST|PUT|PATCH|DELETE, headers, bodyTemplate, saveAs }`. SSRF-guarded (private/loopback/metadata IPs rejected). Response saved as `{ status, ok, body }` to `vars[saveAs]`. Edge: `'success'` on 2xx, `'error'` otherwise. **hubspot_upsert_contact**: `{ email, phone, firstName, lastName, properties, saveAs }`. Creates or updates the run contact in the profile's connected HubSpot portal: the contact already linked by inbox sync, else one matching by email, then phone, is updated; otherwise one is created. An existing contact gets only the fields the node sets (a value that resolves to an empty string is skipped); a new one also takes the Zernio contact's name, email and phone for anything left out. `properties` maps HubSpot internal property names to values (at most 50). Saves `{ id, created }` (or `{ error }`) to `vars[saveAs]` (default `hubspotContact`). Edges: `'success'` | `'error'` (HubSpot not connected, or HubSpot refused the write). **ai**: `{ provider: anthropic|openai|google|mistral|groq|openrouter, model, preset: smart|tools|cheap, systemPrompt, userPromptTemplate, saveAs, temperature, maxTokens, outputType: text|json, tools:[{ name, description, parameters }] }`. Set `provider` + `model` for BYOK (uses your stored API key); omit `provider` for the legacy Telnyx path. Edges: `'success'`, `'tool:<name>'` (model picked a tool), `'error'`. **handoff**: `{ note, assignTo }`. Terminates the run as `exited`, flags the conversation for a human operator. **start_call**: `{ to, forwardTo, requirePermissionFirst, recordingEnabled, saveAs }`. WhatsApp-only. `forwardTo` can be `tel:+E164`, `sip:user@host`, or `wss://…` (AI voice agent). Edges: `'success'`, `'permission_required'`, `'failed'`. **a_b_split**: `{ percentage: number 0-100 (default 50) }`. Random branch picker. Edges: `'a'` (with probability `percentage/100`), `'b'`. **set_field**: `{ field, value }`. Persistent custom field on the Contact (vs `set_variable` which is run-scoped). Field name is sanitized to `[A-Za-z0-9_]`. No-op on `api_call` runs (no contact). **enroll_sequence**: `{ sequenceId, saveAs }`. Enrolls the run's contact into a Sequence. Edges: `'success'`, `'error'`. **add_tag** / **remove_tag**: `{ tag }`. Push or pull a tag on the Contact. No-op on `api_call` runs. **end**: no config. Terminates the run as `completed`. | [optional] |
9
+ | **config** | **Hash<String, Object>** | Type-specific settings. All string fields support `{{variable}}` interpolation against the run's variable bag (resolved at execution time). **trigger**: `{ triggerType: inbound_message|api_call|whatsapp_event|referral|story_mention|comment|reaction|lead_received, keywords:[string], matchType: any|contains|exact|regex, onlyFirstMessage:boolean, eventType: message_sent|message_delivered|message_read|message_failed|reaction, referral:{ ref, matchType: exact|prefix|any }, reaction:{ emojis:[string] }, comment:{ keywords:[string], matchType: any|contains|exact|regex, platformPostId }, leadReceived:{ formIds:[string], pageAccountIds:[string], consentCheckboxKey, defaultCountry, allowCrossProfile:boolean }, cooldownHours:int (1-720) }`. Default `triggerType` is `inbound_message` for legacy nodes. A workflow starts only on events of its own trigger type: `inbound_message` on a message, `referral` on an ig.me / m.me / click-to-message ad referral (standalone, or the first message carrying one; the two are deduplicated per conversation within 60 seconds), `story_mention` on an Instagram story mention, `reaction` on a reaction (Instagram, Facebook, WhatsApp, Telegram groups), `comment` on an Instagram or Facebook comment (the run starts with no conversation and its first `send_message`, which must be text (with optional buttons or quick replies) or cards and must follow the trigger directly (checked on save; on some Instagram accounts Meta refuses buttons and cards to commenters who do not follow the account), is sent as a private reply to the comment; the run then continues in the conversation that reply opens; when an active comment automation's keywords match the comment, the automation answers and the workflow does not start), `whatsapp_event` on a WhatsApp status of a message we sent (filtered by `eventType`), `api_call` only via `POST /v1/workflows/{workflowId}/trigger`, and `lead_received` (WhatsApp workflows only) when a Meta lead ad form is submitted. A `lead_received` trigger needs `leadReceived.consentCheckboxKey` and at least one of `formIds` or `pageAccountIds`; a form scope wins over a Page scope, then the earliest activated workflow. It starts only for leads submitted in the last hour and after the workflow was activated, whose consent checkbox (the form's custom disclaimer, see `POST /v1/ads/lead-forms`) is ticked, and whose phone number parses to a valid international number (`defaultCountry`, ISO 3166 alpha-2, defaults to the country of the workflow's WhatsApp number); otherwise the lead is marked `unreachable`. The Page and the WhatsApp number must be in the same profile unless `allowCrossProfile` is true. Every send or call reached first from the trigger must be a WhatsApp template (checked on save). `referral.matchType` defaults to `any`. `cooldownHours` (inbound_message, referral, story_mention, reaction, whatsapp_event and lead_received, where it defaults to 24) stops the same contact from starting the workflow again inside the window. A `whatsapp_event` workflow never starts on the status of a message a workflow, sequence or comment automation sent. A redelivered platform event never starts the same workflow twice. **Variables** available from the start of every run (absent values are `''`): `lastMessage`, `inboundText`, `triggerText`, `conversationId`, `contact.name`, `contact.phone`, `contact.handle`, `contact.tags` (array), `contact.fields` (the contact's custom fields object), `contact.lastInteractionAt` (ISO date), `contact.lastInteractionHoursAgo` (number), `contact.isFollower` (Instagram, from the stored profile: true, false or `''` when unknown), `referral.ref`, `referral.source`, `referral.type`, `referral.adId`, `referral.adTitle` (the ad title or headline Meta sent), `referral.adName` (the synced ad's name, else `referral.adTitle`), `referral.campaignName` (the synced ad's campaign), `postback.payload`, `postback.title`, `quickReply.payload`, `quickReply.title`, `story.id`, `story.url`, `comment.id`, `comment.text`, `comment.platformPostId`, `reaction.emoji`, `reaction.action` (added|removed). `api_call` runs also get the request's `variables`, merged over these. `lead_received` runs also get `lead.id`, `lead.leadgenId`, `lead.formId`, `lead.formName`, `lead.adId`, `lead.adsetId`, `lead.campaignId` and every form answer by its key (`lead.full_name`, `lead.email`, `lead.phone_number`). Template `variableMapping` entries with `field: custom` interpolate `{{...}}` in `customValue`. An array or object interpolated into text renders as JSON. **send_message**: `{ messageType: text|template|media|interactive|cards, text, template, media:{mediaType:image|video|audio|document, url,caption}, interactive, buttons, quickReplies, messageTag }`. `template` is `{name,language,variableMapping}` for `messageType: template` and `{ type: generic, elements:[{ title, subtitle, imageUrl, buttons }] }` (1 to 10 cards) for `messageType: cards`. `template` and `interactive` are WhatsApp-only. `interactive.type` is inferred from the payload shape when omitted; payloads with neither `type` nor an inferable shape are rejected. Facebook and Instagram only (rejected with a 400 on other platforms; WhatsApp keeps `interactive`): `cards`, plus `buttons` on `text` (cards carry their own buttons) and `quickReplies` / `messageTag` on `text`, `media` and `cards`. `media` takes no `buttons` (a 400 at save). `buttons:[{ type: url|postback|phone, title, url, payload, phone, workflowId }]` (1 to 3, text only and the text then 640 characters at most, sent as Meta's button_template, `phone` Facebook-only, not inside cards), `quickReplies:[{ title, payload, imageUrl, workflowId }]` (1 to 13, not combined with `buttons`). `messageTag` is not available: a workflow only sends within the 24h window, and `HUMAN_AGENT` is rejected with a 400 because it is only for replies typed by a person. Titles are capped at 20 characters (80 for card titles and subtitles). A postback button or quick reply with no `payload` gets `zernio:workflow:<this workflow id>`, so a tap answers this workflow's pending `wait_for_reply` or restarts it; with `workflowId` (a 24-hex workflow id, not combined with `payload`) the tap starts that workflow instead. **wait_for_reply**: `{ timeoutMinutes:int (max 43200), saveAs:string }`. Resume via the `'reply'` edge on inbound, or `'timeout'` edge after `timeoutMinutes` of silence. On Facebook and Instagram a button tap sets `{{postback.payload}}` / `{{postback.title}}` and a quick reply tap sets `{{quickReply.payload}}` / `{{quickReply.title}}`; each reply clears the previous tap. **condition**: `{ rules:[{ id, variable, operator: equals|not_equals|contains|not_contains|starts_with|ends_with|exists|not_exists|matches|greater_than|less_than|greater_or_equal|less_or_equal|before|after|has_tag|not_has_tag|is_true|is_false, value }] }`. First matching rule takes its `id` as the sourceHandle; otherwise `'default'`. Text operators compare case-insensitively. `greater_than`, `less_than`, `greater_or_equal` and `less_or_equal` compare numbers (a non-numeric side is false); `before` and `after` compare ISO dates; `has_tag` and `not_has_tag` test whether an array variable (such as `contact.tags`) contains `value`; `is_true` and `is_false` take no value. **set_variable**: `{ assignments:[{ name, value }] }`. Run-scoped (lives only for this execution; use `set_field` for persistent values). **delay**: `{ delayMinutes:int (max 43200) }`. Suspends the run, resumes via timer. **webhook**: `{ url, method: GET|POST|PUT|PATCH|DELETE, headers, bodyTemplate, saveAs }`. SSRF-guarded (private/loopback/metadata IPs rejected). Response saved as `{ status, ok, body }` to `vars[saveAs]`. Edge: `'success'` on 2xx, `'error'` otherwise. **hubspot_upsert_contact**: `{ email, phone, firstName, lastName, properties, saveAs }`. Creates or updates the run contact in the profile's connected HubSpot portal: the contact already linked by inbox sync, else one matching by email, then phone, is updated; otherwise one is created. An existing contact gets only the fields the node sets (a value that resolves to an empty string is skipped); a new one also takes the Zernio contact's name, email and phone for anything left out. `properties` maps HubSpot internal property names to values (at most 50). Saves `{ id, created }` (or `{ error }`) to `vars[saveAs]` (default `hubspotContact`). Edges: `'success'` | `'error'` (HubSpot not connected, or HubSpot refused the write). **ai**: `{ provider: anthropic|openai|google|mistral|groq|openrouter, model, preset: smart|tools|cheap, systemPrompt, userPromptTemplate, saveAs, temperature, maxTokens, outputType: text|json, tools:[{ name, description, parameters }] }`. Set `provider` + `model` for BYOK (uses your stored API key); omit `provider` for the legacy Telnyx path. Edges: `'success'`, `'tool:<name>'` (model picked a tool), `'error'`. **handoff**: `{ note, assignTo }`. Terminates the run as `exited`, flags the conversation for a human operator. **start_call**: `{ to, forwardTo, requirePermissionFirst, recordingEnabled, saveAs }`. WhatsApp-only. `forwardTo` can be `tel:+E164`, `sip:user@host`, or `wss://…` (AI voice agent). Edges: `'success'`, `'permission_required'`, `'failed'`. **a_b_split**: `{ percentage: number 0-100 (default 50) }`. Random branch picker. Edges: `'a'` (with probability `percentage/100`), `'b'`. **set_field**: `{ field, value }`. Persistent custom field on the Contact (vs `set_variable` which is run-scoped). Field name is sanitized to `[A-Za-z0-9_]`. No-op on `api_call` runs (no contact). **enroll_sequence**: `{ sequenceId, saveAs }`. Enrolls the run's contact into a Sequence. Edges: `'success'`, `'error'`. **add_tag** / **remove_tag**: `{ tag }`. Push or pull a tag on the Contact. No-op on `api_call` runs. **end**: no config. Terminates the run as `completed`. | [optional] |
10
10
  | **position** | [**WorkflowNodePosition**](WorkflowNodePosition.md) | | [optional] |
11
11
  | **label** | **String** | Optional display name shown on the builder canvas and inspector, falling back to the node type when absent. The nodes array is replaced wholesale on update, so it must be resent to be kept. | [optional] |
12
12
 
@@ -21,7 +21,7 @@ module Zernio
21
21
  # SMS only: sent as MMS media, one media_url per attachment. Each url must be public http(s); JPEG, PNG, GIF, WEBP, MP4 or 3GPP under 1 MB (checked at create when the host answers a HEAD request; Telnyx enforces the 1 MB total per message at send).
22
22
  attr_accessor :attachments
23
23
 
24
- # Instagram and Facebook only. Meta message tag sent with every recipient message (messaging_type MESSAGE_TAG) so the broadcast can reach people outside the 24h window. Instagram accepts HUMAN_AGENT only. Rejected with a 400 on any other platform.
24
+ # Not usable: a broadcast only reaches people within the 24h window. HUMAN_AGENT is rejected with a 400 because it is only for replies typed by a person, and Meta retired the other tags.
25
25
  attr_accessor :message_tag
26
26
 
27
27
  class EnumAttributeValidator
@@ -75,7 +75,7 @@ module Zernio
75
75
  # Facebook messaging type. Required when using messageTag.
76
76
  attr_accessor :messaging_type
77
77
 
78
- # Facebook message tag for messaging outside 24h window. Requires messagingType MESSAGE_TAG. Instagram only supports HUMAN_AGENT.
78
+ # Facebook and Instagram. To reply after the 24h window, send HUMAN_AGENT with messagingType MESSAGE_TAG: it works up to 7 days after the person's last message, for replies typed by a person only (Meta does not allow it on automated messages). Meta retired the other tags, so they fail.
79
79
  attr_accessor :message_tag
80
80
 
81
81
  # Platform message ID to quote-reply to. For WhatsApp, pass the wamid; for Telegram, the Telegram message ID (delivered as message.platformMessageId on webhooks, and as `id` on each entry of the list-messages endpoint). On Slack it threads the reply (thread_ts) instead of quoting. Instagram and Facebook Messenger do not support send-side quote replies: the message is sent without a quote and the successful response includes a warnings entry with code ignored_field and param replyTo. Other platforms without send-side reply support ignore this field.
@@ -22,7 +22,7 @@ module Zernio
22
22
  # Node kind. The 17 supported types break into four groups: messaging (send_message), control flow (trigger, condition, delay, wait_for_reply, a_b_split, end), data ops (set_variable, set_field, add_tag, remove_tag, enroll_sequence), integrations (webhook, hubspot_upsert_contact, ai, handoff, start_call).
23
23
  attr_accessor :type
24
24
 
25
- # Type-specific settings. All string fields support `{{variable}}` interpolation against the run's variable bag (resolved at execution time). **trigger**: `{ triggerType: inbound_message|api_call|whatsapp_event|referral|story_mention|comment|reaction|lead_received, keywords:[string], matchType: any|contains|exact|regex, onlyFirstMessage:boolean, eventType: message_sent|message_delivered|message_read|message_failed|reaction, referral:{ ref, matchType: exact|prefix|any }, reaction:{ emojis:[string] }, comment:{ keywords:[string], matchType: any|contains|exact|regex, platformPostId }, leadReceived:{ formIds:[string], pageAccountIds:[string], consentCheckboxKey, defaultCountry, allowCrossProfile:boolean }, cooldownHours:int (1-720) }`. Default `triggerType` is `inbound_message` for legacy nodes. A workflow starts only on events of its own trigger type: `inbound_message` on a message, `referral` on an ig.me / m.me / click-to-message ad referral (standalone, or the first message carrying one; the two are deduplicated per conversation within 60 seconds), `story_mention` on an Instagram story mention, `reaction` on a reaction (Instagram, Facebook, WhatsApp, Telegram groups), `comment` on an Instagram or Facebook comment (the run starts with no conversation and its first `send_message`, which must be text (with optional buttons or quick replies) or cards and must follow the trigger directly (checked on save; on some Instagram accounts Meta refuses buttons and cards to commenters who do not follow the account), is sent as a private reply to the comment; the run then continues in the conversation that reply opens; when an active comment automation's keywords match the comment, the automation answers and the workflow does not start), `whatsapp_event` on a WhatsApp status of a message we sent (filtered by `eventType`), `api_call` only via `POST /v1/workflows/{workflowId}/trigger`, and `lead_received` (WhatsApp workflows only) when a Meta lead ad form is submitted. A `lead_received` trigger needs `leadReceived.consentCheckboxKey` and at least one of `formIds` or `pageAccountIds`; a form scope wins over a Page scope, then the earliest activated workflow. It starts only for leads submitted in the last hour and after the workflow was activated, whose consent checkbox (the form's custom disclaimer, see `POST /v1/ads/lead-forms`) is ticked, and whose phone number parses to a valid international number (`defaultCountry`, ISO 3166 alpha-2, defaults to the country of the workflow's WhatsApp number); otherwise the lead is marked `unreachable`. The Page and the WhatsApp number must be in the same profile unless `allowCrossProfile` is true. Every send or call reached first from the trigger must be a WhatsApp template (checked on save). `referral.matchType` defaults to `any`. `cooldownHours` (inbound_message, referral, story_mention, reaction, whatsapp_event and lead_received, where it defaults to 24) stops the same contact from starting the workflow again inside the window. A `whatsapp_event` workflow never starts on the status of a message a workflow, sequence or comment automation sent. A redelivered platform event never starts the same workflow twice. **Variables** available from the start of every run (absent values are `''`): `lastMessage`, `inboundText`, `triggerText`, `conversationId`, `contact.name`, `contact.phone`, `contact.handle`, `contact.tags` (array), `contact.fields` (the contact's custom fields object), `contact.lastInteractionAt` (ISO date), `contact.lastInteractionHoursAgo` (number), `contact.isFollower` (Instagram, from the stored profile: true, false or `''` when unknown), `referral.ref`, `referral.source`, `referral.type`, `referral.adId`, `referral.adTitle` (the ad title or headline Meta sent), `referral.adName` (the synced ad's name, else `referral.adTitle`), `referral.campaignName` (the synced ad's campaign), `postback.payload`, `postback.title`, `quickReply.payload`, `quickReply.title`, `story.id`, `story.url`, `comment.id`, `comment.text`, `comment.platformPostId`, `reaction.emoji`, `reaction.action` (added|removed). `api_call` runs also get the request's `variables`, merged over these. `lead_received` runs also get `lead.id`, `lead.leadgenId`, `lead.formId`, `lead.formName`, `lead.adId`, `lead.adsetId`, `lead.campaignId` and every form answer by its key (`lead.full_name`, `lead.email`, `lead.phone_number`). Template `variableMapping` entries with `field: custom` interpolate `{{...}}` in `customValue`. An array or object interpolated into text renders as JSON. **send_message**: `{ messageType: text|template|media|interactive|cards, text, template, media:{mediaType:image|video|audio|document, url,caption}, interactive, buttons, quickReplies, messageTag }`. `template` is `{name,language,variableMapping}` for `messageType: template` and `{ type: generic, elements:[{ title, subtitle, imageUrl, buttons }] }` (1 to 10 cards) for `messageType: cards`. `template` and `interactive` are WhatsApp-only. `interactive.type` is inferred from the payload shape when omitted; payloads with neither `type` nor an inferable shape are rejected. Facebook and Instagram only (rejected with a 400 on other platforms; WhatsApp keeps `interactive`): `cards`, plus `buttons` on `text` (cards carry their own buttons) and `quickReplies` / `messageTag` on `text`, `media` and `cards`. `media` takes no `buttons` (a 400 at save). `buttons:[{ type: url|postback|phone, title, url, payload, phone, workflowId }]` (1 to 3, text only and the text then 640 characters at most, sent as Meta's button_template, `phone` Facebook-only, not inside cards), `quickReplies:[{ title, payload, imageUrl, workflowId }]` (1 to 13, not combined with `buttons`) and `messageTag: HUMAN_AGENT|CONFIRMED_EVENT_UPDATE|POST_PURCHASE_UPDATE|ACCOUNT_UPDATE` (Instagram accepts only `HUMAN_AGENT`). Titles are capped at 20 characters (80 for card titles and subtitles). A postback button or quick reply with no `payload` gets `zernio:workflow:<this workflow id>`, so a tap answers this workflow's pending `wait_for_reply` or restarts it; with `workflowId` (a 24-hex workflow id, not combined with `payload`) the tap starts that workflow instead. **wait_for_reply**: `{ timeoutMinutes:int (max 43200), saveAs:string }`. Resume via the `'reply'` edge on inbound, or `'timeout'` edge after `timeoutMinutes` of silence. On Facebook and Instagram a button tap sets `{{postback.payload}}` / `{{postback.title}}` and a quick reply tap sets `{{quickReply.payload}}` / `{{quickReply.title}}`; each reply clears the previous tap. **condition**: `{ rules:[{ id, variable, operator: equals|not_equals|contains|not_contains|starts_with|ends_with|exists|not_exists|matches|greater_than|less_than|greater_or_equal|less_or_equal|before|after|has_tag|not_has_tag|is_true|is_false, value }] }`. First matching rule takes its `id` as the sourceHandle; otherwise `'default'`. Text operators compare case-insensitively. `greater_than`, `less_than`, `greater_or_equal` and `less_or_equal` compare numbers (a non-numeric side is false); `before` and `after` compare ISO dates; `has_tag` and `not_has_tag` test whether an array variable (such as `contact.tags`) contains `value`; `is_true` and `is_false` take no value. **set_variable**: `{ assignments:[{ name, value }] }`. Run-scoped (lives only for this execution; use `set_field` for persistent values). **delay**: `{ delayMinutes:int (max 43200) }`. Suspends the run, resumes via timer. **webhook**: `{ url, method: GET|POST|PUT|PATCH|DELETE, headers, bodyTemplate, saveAs }`. SSRF-guarded (private/loopback/metadata IPs rejected). Response saved as `{ status, ok, body }` to `vars[saveAs]`. Edge: `'success'` on 2xx, `'error'` otherwise. **hubspot_upsert_contact**: `{ email, phone, firstName, lastName, properties, saveAs }`. Creates or updates the run contact in the profile's connected HubSpot portal: the contact already linked by inbox sync, else one matching by email, then phone, is updated; otherwise one is created. An existing contact gets only the fields the node sets (a value that resolves to an empty string is skipped); a new one also takes the Zernio contact's name, email and phone for anything left out. `properties` maps HubSpot internal property names to values (at most 50). Saves `{ id, created }` (or `{ error }`) to `vars[saveAs]` (default `hubspotContact`). Edges: `'success'` | `'error'` (HubSpot not connected, or HubSpot refused the write). **ai**: `{ provider: anthropic|openai|google|mistral|groq|openrouter, model, preset: smart|tools|cheap, systemPrompt, userPromptTemplate, saveAs, temperature, maxTokens, outputType: text|json, tools:[{ name, description, parameters }] }`. Set `provider` + `model` for BYOK (uses your stored API key); omit `provider` for the legacy Telnyx path. Edges: `'success'`, `'tool:<name>'` (model picked a tool), `'error'`. **handoff**: `{ note, assignTo }`. Terminates the run as `exited`, flags the conversation for a human operator. **start_call**: `{ to, forwardTo, requirePermissionFirst, recordingEnabled, saveAs }`. WhatsApp-only. `forwardTo` can be `tel:+E164`, `sip:user@host`, or `wss://…` (AI voice agent). Edges: `'success'`, `'permission_required'`, `'failed'`. **a_b_split**: `{ percentage: number 0-100 (default 50) }`. Random branch picker. Edges: `'a'` (with probability `percentage/100`), `'b'`. **set_field**: `{ field, value }`. Persistent custom field on the Contact (vs `set_variable` which is run-scoped). Field name is sanitized to `[A-Za-z0-9_]`. No-op on `api_call` runs (no contact). **enroll_sequence**: `{ sequenceId, saveAs }`. Enrolls the run's contact into a Sequence. Edges: `'success'`, `'error'`. **add_tag** / **remove_tag**: `{ tag }`. Push or pull a tag on the Contact. No-op on `api_call` runs. **end**: no config. Terminates the run as `completed`.
25
+ # Type-specific settings. All string fields support `{{variable}}` interpolation against the run's variable bag (resolved at execution time). **trigger**: `{ triggerType: inbound_message|api_call|whatsapp_event|referral|story_mention|comment|reaction|lead_received, keywords:[string], matchType: any|contains|exact|regex, onlyFirstMessage:boolean, eventType: message_sent|message_delivered|message_read|message_failed|reaction, referral:{ ref, matchType: exact|prefix|any }, reaction:{ emojis:[string] }, comment:{ keywords:[string], matchType: any|contains|exact|regex, platformPostId }, leadReceived:{ formIds:[string], pageAccountIds:[string], consentCheckboxKey, defaultCountry, allowCrossProfile:boolean }, cooldownHours:int (1-720) }`. Default `triggerType` is `inbound_message` for legacy nodes. A workflow starts only on events of its own trigger type: `inbound_message` on a message, `referral` on an ig.me / m.me / click-to-message ad referral (standalone, or the first message carrying one; the two are deduplicated per conversation within 60 seconds), `story_mention` on an Instagram story mention, `reaction` on a reaction (Instagram, Facebook, WhatsApp, Telegram groups), `comment` on an Instagram or Facebook comment (the run starts with no conversation and its first `send_message`, which must be text (with optional buttons or quick replies) or cards and must follow the trigger directly (checked on save; on some Instagram accounts Meta refuses buttons and cards to commenters who do not follow the account), is sent as a private reply to the comment; the run then continues in the conversation that reply opens; when an active comment automation's keywords match the comment, the automation answers and the workflow does not start), `whatsapp_event` on a WhatsApp status of a message we sent (filtered by `eventType`), `api_call` only via `POST /v1/workflows/{workflowId}/trigger`, and `lead_received` (WhatsApp workflows only) when a Meta lead ad form is submitted. A `lead_received` trigger needs `leadReceived.consentCheckboxKey` and at least one of `formIds` or `pageAccountIds`; a form scope wins over a Page scope, then the earliest activated workflow. It starts only for leads submitted in the last hour and after the workflow was activated, whose consent checkbox (the form's custom disclaimer, see `POST /v1/ads/lead-forms`) is ticked, and whose phone number parses to a valid international number (`defaultCountry`, ISO 3166 alpha-2, defaults to the country of the workflow's WhatsApp number); otherwise the lead is marked `unreachable`. The Page and the WhatsApp number must be in the same profile unless `allowCrossProfile` is true. Every send or call reached first from the trigger must be a WhatsApp template (checked on save). `referral.matchType` defaults to `any`. `cooldownHours` (inbound_message, referral, story_mention, reaction, whatsapp_event and lead_received, where it defaults to 24) stops the same contact from starting the workflow again inside the window. A `whatsapp_event` workflow never starts on the status of a message a workflow, sequence or comment automation sent. A redelivered platform event never starts the same workflow twice. **Variables** available from the start of every run (absent values are `''`): `lastMessage`, `inboundText`, `triggerText`, `conversationId`, `contact.name`, `contact.phone`, `contact.handle`, `contact.tags` (array), `contact.fields` (the contact's custom fields object), `contact.lastInteractionAt` (ISO date), `contact.lastInteractionHoursAgo` (number), `contact.isFollower` (Instagram, from the stored profile: true, false or `''` when unknown), `referral.ref`, `referral.source`, `referral.type`, `referral.adId`, `referral.adTitle` (the ad title or headline Meta sent), `referral.adName` (the synced ad's name, else `referral.adTitle`), `referral.campaignName` (the synced ad's campaign), `postback.payload`, `postback.title`, `quickReply.payload`, `quickReply.title`, `story.id`, `story.url`, `comment.id`, `comment.text`, `comment.platformPostId`, `reaction.emoji`, `reaction.action` (added|removed). `api_call` runs also get the request's `variables`, merged over these. `lead_received` runs also get `lead.id`, `lead.leadgenId`, `lead.formId`, `lead.formName`, `lead.adId`, `lead.adsetId`, `lead.campaignId` and every form answer by its key (`lead.full_name`, `lead.email`, `lead.phone_number`). Template `variableMapping` entries with `field: custom` interpolate `{{...}}` in `customValue`. An array or object interpolated into text renders as JSON. **send_message**: `{ messageType: text|template|media|interactive|cards, text, template, media:{mediaType:image|video|audio|document, url,caption}, interactive, buttons, quickReplies, messageTag }`. `template` is `{name,language,variableMapping}` for `messageType: template` and `{ type: generic, elements:[{ title, subtitle, imageUrl, buttons }] }` (1 to 10 cards) for `messageType: cards`. `template` and `interactive` are WhatsApp-only. `interactive.type` is inferred from the payload shape when omitted; payloads with neither `type` nor an inferable shape are rejected. Facebook and Instagram only (rejected with a 400 on other platforms; WhatsApp keeps `interactive`): `cards`, plus `buttons` on `text` (cards carry their own buttons) and `quickReplies` / `messageTag` on `text`, `media` and `cards`. `media` takes no `buttons` (a 400 at save). `buttons:[{ type: url|postback|phone, title, url, payload, phone, workflowId }]` (1 to 3, text only and the text then 640 characters at most, sent as Meta's button_template, `phone` Facebook-only, not inside cards), `quickReplies:[{ title, payload, imageUrl, workflowId }]` (1 to 13, not combined with `buttons`). `messageTag` is not available: a workflow only sends within the 24h window, and `HUMAN_AGENT` is rejected with a 400 because it is only for replies typed by a person. Titles are capped at 20 characters (80 for card titles and subtitles). A postback button or quick reply with no `payload` gets `zernio:workflow:<this workflow id>`, so a tap answers this workflow's pending `wait_for_reply` or restarts it; with `workflowId` (a 24-hex workflow id, not combined with `payload`) the tap starts that workflow instead. **wait_for_reply**: `{ timeoutMinutes:int (max 43200), saveAs:string }`. Resume via the `'reply'` edge on inbound, or `'timeout'` edge after `timeoutMinutes` of silence. On Facebook and Instagram a button tap sets `{{postback.payload}}` / `{{postback.title}}` and a quick reply tap sets `{{quickReply.payload}}` / `{{quickReply.title}}`; each reply clears the previous tap. **condition**: `{ rules:[{ id, variable, operator: equals|not_equals|contains|not_contains|starts_with|ends_with|exists|not_exists|matches|greater_than|less_than|greater_or_equal|less_or_equal|before|after|has_tag|not_has_tag|is_true|is_false, value }] }`. First matching rule takes its `id` as the sourceHandle; otherwise `'default'`. Text operators compare case-insensitively. `greater_than`, `less_than`, `greater_or_equal` and `less_or_equal` compare numbers (a non-numeric side is false); `before` and `after` compare ISO dates; `has_tag` and `not_has_tag` test whether an array variable (such as `contact.tags`) contains `value`; `is_true` and `is_false` take no value. **set_variable**: `{ assignments:[{ name, value }] }`. Run-scoped (lives only for this execution; use `set_field` for persistent values). **delay**: `{ delayMinutes:int (max 43200) }`. Suspends the run, resumes via timer. **webhook**: `{ url, method: GET|POST|PUT|PATCH|DELETE, headers, bodyTemplate, saveAs }`. SSRF-guarded (private/loopback/metadata IPs rejected). Response saved as `{ status, ok, body }` to `vars[saveAs]`. Edge: `'success'` on 2xx, `'error'` otherwise. **hubspot_upsert_contact**: `{ email, phone, firstName, lastName, properties, saveAs }`. Creates or updates the run contact in the profile's connected HubSpot portal: the contact already linked by inbox sync, else one matching by email, then phone, is updated; otherwise one is created. An existing contact gets only the fields the node sets (a value that resolves to an empty string is skipped); a new one also takes the Zernio contact's name, email and phone for anything left out. `properties` maps HubSpot internal property names to values (at most 50). Saves `{ id, created }` (or `{ error }`) to `vars[saveAs]` (default `hubspotContact`). Edges: `'success'` | `'error'` (HubSpot not connected, or HubSpot refused the write). **ai**: `{ provider: anthropic|openai|google|mistral|groq|openrouter, model, preset: smart|tools|cheap, systemPrompt, userPromptTemplate, saveAs, temperature, maxTokens, outputType: text|json, tools:[{ name, description, parameters }] }`. Set `provider` + `model` for BYOK (uses your stored API key); omit `provider` for the legacy Telnyx path. Edges: `'success'`, `'tool:<name>'` (model picked a tool), `'error'`. **handoff**: `{ note, assignTo }`. Terminates the run as `exited`, flags the conversation for a human operator. **start_call**: `{ to, forwardTo, requirePermissionFirst, recordingEnabled, saveAs }`. WhatsApp-only. `forwardTo` can be `tel:+E164`, `sip:user@host`, or `wss://…` (AI voice agent). Edges: `'success'`, `'permission_required'`, `'failed'`. **a_b_split**: `{ percentage: number 0-100 (default 50) }`. Random branch picker. Edges: `'a'` (with probability `percentage/100`), `'b'`. **set_field**: `{ field, value }`. Persistent custom field on the Contact (vs `set_variable` which is run-scoped). Field name is sanitized to `[A-Za-z0-9_]`. No-op on `api_call` runs (no contact). **enroll_sequence**: `{ sequenceId, saveAs }`. Enrolls the run's contact into a Sequence. Edges: `'success'`, `'error'`. **add_tag** / **remove_tag**: `{ tag }`. Push or pull a tag on the Contact. No-op on `api_call` runs. **end**: no config. Terminates the run as `completed`.
26
26
  attr_accessor :config
27
27
 
28
28
  attr_accessor :position
@@ -11,5 +11,5 @@ Generator version: 7.19.0
11
11
  =end
12
12
 
13
13
  module Zernio
14
- VERSION = '0.0.1588'
14
+ VERSION = '0.0.1589'
15
15
  end