Twilio Send ExecModule
Overview
TwilioSendModule creates one outbound Twilio Message resource for SMS, MMS, or WhatsApp. Version 2.0 replaces the former catalog-empty and mockable implementation with strict request validation, bounded transport, IntegrationAccount-only credentials, verified provider results, and secret-safe failures.
The module reports success only after Twilio returns a valid SM or MM Message SID and an initial status. Message creation is an external, non-idempotent action. The module never fabricates a SID and never retries automatically after rate limits, provider failures, timeouts, or ambiguous network outcomes.
Usage
- Create or select a Twilio account authorized for Programmable Messaging.
- Store the Account SID and Auth Token in a ValkyrAI
IntegrationAccountand set its status toREADY. - Bind that account through
ExecModuleConfig.authConfig.integrationAccount. - Select
SMSorWHATSAPP, configure an E.164 recipient, and provide an explicit sender or Messaging Service SID. - Supply a body, HTTPS media URLs, or a Content Template SID. Do not combine a body with a Content Template.
- Apply outbound approval where workflow policy requires it, then reconcile the Twilio Message SID before manually retrying an ambiguous failure.
Inputs
| Name | Type | Required | Description | Constraints |
|---|---|---|---|---|
channel | string | Yes | SMS or WHATSAPP. | Case-insensitive; normalized to uppercase. |
to | string | Yes | Recipient phone number. | E.164 format. The module adds whatsapp: for WhatsApp. |
from | string | Conditional | Twilio sender phone number. | E.164 format; required when messaging_service_sid is absent. |
messaging_service_sid | string | Conditional | Twilio Messaging Service. | MG followed by 32 hexadecimal characters. |
body | string | Conditional | SMS, MMS, or free-form WhatsApp content. | 1–1,600 Unicode code points; cannot be combined with content_sid. |
media_urls | array of strings | No | Media Twilio retrieves for the message. | At most ten HTTPS URLs; embedded credentials and fragments are rejected. |
content_sid | string | Conditional | Approved Twilio Content Template. | HX followed by 32 hexadecimal characters; cannot be combined with body or media. |
content_variables | object | No | Values for a Content Template. | Requires content_sid; serialized once as the ContentVariables JSON object. |
At least one of body, media_urls, or content_sid is required. Legacy whatsapp_template and template_vars names are accepted as aliases for migration, but new workflows should use the canonical names above. A legacy mock value is rejected.
Outputs
| Name | Type | When present | Description |
|---|---|---|---|
twilio.message.sid | string | Verified success | Twilio SM or MM Message SID. |
twilio.message.status | string | Always | Initial Twilio status such as queued, or ERROR on failure. |
twilio.message.channel | string | Verified success | Normalized SMS or WHATSAPP. |
The initial status confirms that Twilio accepted or created the Message resource; it is not proof of delivery. Delivery tracking belongs in a status-callback workflow or an explicit message-read operation.
IntegrationAccount Requirements
| Setting | Requirement |
|---|---|
| Provider | Twilio Programmable Messaging |
| Status | READY |
apiKey | Encrypted Twilio Account SID beginning with AC |
password | Encrypted Twilio Auth Token |
| Relationship | Bind through ExecModuleConfig.authConfig.integrationAccount |
Do not place the Auth Token, Account SID, or generated Basic authorization value in payload parameters, workflow content, logs, errors, or documentation examples. Restricted Twilio API keys and OAuth credentials are not mapped by this module's v2 credential contract.
Configuration
Illustrative normalized configuration:
{
"version": "2.0.0",
"authConfig": {
"authStrategy": 1,
"integrationAccount": "integration-account:twilio-production"
},
"payloadConfig": {
"parameters": "{\"channel\":\"SMS\",\"to\":\"+14155550123\",\"from\":\"+14155550999\",\"body\":\"Your order is ready.\"}"
}
}
The account value is a symbolic secure relationship, not a credential. The default transport uses a 10-second connection timeout and a 30-second read timeout. Redirects and retries are not part of the module-level send contract.
Operations
TwilioSendModule performs one provider operation: POST /2010-04-01/Accounts/{AccountSid}/Messages.json.
| Shape | Provider fields | Side effect |
|---|---|---|
| SMS | To, From or MessagingServiceSid, Body | Creates one text Message resource. |
| MMS | SMS fields plus one or more MediaUrl fields | Creates one media-bearing Message resource. |
| WhatsApp free-form | WhatsApp-prefixed To/From plus Body | Creates one WhatsApp message subject to the conversation window and account policy. |
| Content Template | Addresses plus ContentSid and optional ContentVariables | Creates one templated Message resource. |
Bulk send, scheduling, message lookup, delivery callbacks, redaction, deletion, and Messaging Service management are not implemented by this module.
Errors and Failure Modes
| Failure | Cause | Retry guidance |
|---|---|---|
| Validation failure | Missing content, invalid E.164 number or SID, insecure media URL, conflicting body/template inputs, or a legacy mock request. | Correct configuration; no Twilio request was sent. |
| IntegrationAccount failure | No bound account, non-READY status, malformed Account SID, or missing Auth Token. | Repair the secure account binding; no Twilio request was sent. |
| HTTP 400/403/404 | Invalid payload, account policy, sender, recipient, template, media, or resource state. | Correct the request or account before a deliberate new attempt. |
| HTTP 401 | Invalid, expired, or rotated Account SID/Auth Token pair. | Rotate the IntegrationAccount credentials before retrying. |
| HTTP 429 | Provider rate limit. | Reconcile provider state and retry later; the module does not retry automatically. |
| HTTP 5xx or network failure | Provider or transport failure with an ambiguous create boundary. | Search Twilio message records before a deliberate retry to avoid duplicates. |
| Invalid 2xx response | Missing or malformed Message SID or status. | Treat as failure and inspect provider compatibility; success is not recorded. |
Provider response bodies may contain message content, phone numbers, or credential-like values. Failures therefore expose only a sanitized HTTP status or bounded local validation message.
Example
Send one WhatsApp Content Template through a Messaging Service:
{
"channel": "WHATSAPP",
"to": "+14155550123",
"messaging_service_sid": "MGabcdef0123456789abcdef0123456789",
"content_sid": "HX0123456789abcdef0123456789abcdef",
"content_variables": {
"1": "22 July 2026",
"2": "3:15pm"
}
}
Expected result shape after Twilio returns a valid Message resource:
{
"twilio.message.sid": "SMabcdef0123456789abcdef0123456789",
"twilio.message.status": "queued",
"twilio.message.channel": "WHATSAPP"
}
Notes
- Pagination: not applicable; one execution attempts one Message creation.
- Limits: the module caps content at 1,600 Unicode code points and media at ten HTTPS URLs. Twilio and carrier/channel rules may impose stricter limits, segmentation, type, size, or template requirements.
- Rate limits: HTTP 429 is surfaced without retrying. Reconcile whether Twilio created a Message before any new attempt.
- Idempotency: Twilio Message creation has no module-level idempotency key. A workflow retry can create a duplicate message.
- API constraints: sender registration, WhatsApp session windows, template approval, regional policy, carrier filtering, and media retrieval remain provider-controlled.
- Destructive behavior: the operation sends customer-facing content and may incur provider charges. The module cannot recall or compensate a delivered message.
- Observability: EventLogs record validation, submission, verified Message SID, or a sanitized failure. Phone numbers, content, credentials, and provider bodies are excluded.
- Unverified boundary: deterministic tests cover account binding, exact form construction, validation, template-variable serialization, response mapping, non-retry behavior, metadata serialization, and redaction. Live Twilio execution requires separately authorized service credentials and is not exercised in repository tests.
See Twilio's official Messages resource and WhatsApp quickstart for provider-side requirements.